mirror of
https://github.com/Cisco-Talos/clamav.git
synced 2025-10-19 10:23:17 +00:00
Merge branch 'Cisco-Talos:main' into add-selfcheck
This commit is contained in:
commit
1f1149b0a8
174 changed files with 13455 additions and 4072 deletions
|
@ -19,7 +19,7 @@ cmake_policy(SET CMP0087 NEW) # support generator expressions in install(CODE) a
|
||||||
# For release candidate: set(VERSION_SUFFIX "-rc")
|
# For release candidate: set(VERSION_SUFFIX "-rc")
|
||||||
# For release: set(VERSION_SUFFIX "")
|
# For release: set(VERSION_SUFFIX "")
|
||||||
string(TIMESTAMP TODAY "%Y%m%d")
|
string(TIMESTAMP TODAY "%Y%m%d")
|
||||||
set(VERSION_SUFFIX "-beta")
|
set(VERSION_SUFFIX "-rc")
|
||||||
|
|
||||||
project( ClamAV
|
project( ClamAV
|
||||||
VERSION "1.5.0"
|
VERSION "1.5.0"
|
||||||
|
@ -63,6 +63,8 @@ elseif(APPLE OR CMAKE_SYSTEM_NAME MATCHES "BSD")
|
||||||
set(C_BSD 1)
|
set(C_BSD 1)
|
||||||
elseif(CMAKE_SYSTEM_NAME MATCHES "AIX")
|
elseif(CMAKE_SYSTEM_NAME MATCHES "AIX")
|
||||||
set(AIX TRUE)
|
set(AIX TRUE)
|
||||||
|
elseif(CMAKE_SYSTEM_NAME STREQUAL "GNU")
|
||||||
|
set(C_GNU_HURD 1)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# Git optionally used to add commit info into build to differentiate in bug reports.
|
# Git optionally used to add commit info into build to differentiate in bug reports.
|
||||||
|
@ -196,7 +198,7 @@ else()
|
||||||
set(USING_CLANG OFF)
|
set(USING_CLANG OFF)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(C_LINUX)
|
if(C_LINUX OR C_GNU_HURD)
|
||||||
if(CMAKE_COMPILER_IS_GNUCXX OR USING_CLANG)
|
if(CMAKE_COMPILER_IS_GNUCXX OR USING_CLANG)
|
||||||
# Set _GNU_SOURCE for O_LARGEFILE, O_CLOEXEC, O_DIRECTORY, O_NOFOLLOW, etc flags on older systems
|
# Set _GNU_SOURCE for O_LARGEFILE, O_CLOEXEC, O_DIRECTORY, O_NOFOLLOW, etc flags on older systems
|
||||||
# (pre POSIX.1-2008: glibc 2.11 and earlier). #4042
|
# (pre POSIX.1-2008: glibc 2.11 and earlier). #4042
|
||||||
|
|
7
Cargo.lock
generated
7
Cargo.lock
generated
|
@ -395,6 +395,7 @@ dependencies = [
|
||||||
"hex",
|
"hex",
|
||||||
"hex-literal 0.4.1",
|
"hex-literal 0.4.1",
|
||||||
"image",
|
"image",
|
||||||
|
"indexmap 2.10.0",
|
||||||
"inflate",
|
"inflate",
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
|
@ -1097,9 +1098,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "2.9.0"
|
version = "2.10.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
|
checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"equivalent",
|
"equivalent",
|
||||||
"hashbrown 0.15.2",
|
"hashbrown 0.15.2",
|
||||||
|
@ -2122,7 +2123,7 @@ version = "0.22.25"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "10558ed0bd2a1562e630926a2d1f0b98c827da99fabd3fe20920a59642504485"
|
checksum = "10558ed0bd2a1562e630926a2d1f0b98c827da99fabd3fe20920a59642504485"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"indexmap 2.9.0",
|
"indexmap 2.10.0",
|
||||||
"serde",
|
"serde",
|
||||||
"serde_spanned",
|
"serde_spanned",
|
||||||
"toml_datetime",
|
"toml_datetime",
|
||||||
|
|
|
@ -157,12 +157,14 @@ set(CMAKE_SYSROOT /opt/aarch64-wrs-linux-sysroot)
|
||||||
#set(PCRE2_INCLUDE_DIR "/usr/include/")
|
#set(PCRE2_INCLUDE_DIR "/usr/include/")
|
||||||
#set(PCRE2_LIBRARY "/usr/lib64/libpcre2-8.so")
|
#set(PCRE2_LIBRARY "/usr/lib64/libpcre2-8.so")
|
||||||
|
|
||||||
#set(CURSES_INCLUDE_DIR "/usr/include/")
|
set(NCURSES_INCLUDE_DIR "/usr/include/")
|
||||||
#set(CURSES_LIBRARY "/usr/lib/aarch64-linux-gnu/libncurses.a;/usr/lib/aarch64-linux-gnu/libtinfo.a")
|
set(CURSES_LIBRARY "/usr/lib/aarch64-linux-gnu/libncurses.a")
|
||||||
# Tip: You may not need to also link with libtinfo.a, depending on what your distribution provides:
|
set(TINFO_LIBRARY "/usr/lib/aarch64-linux-gnu/libtinfo.a")
|
||||||
#set(CURSES_LIBRARY "/usr/lib/aarch64-linux-gnu/libncurses.a")
|
# Tip: You may not need to also link with libtinfo.a, depending on what your distribution provides.
|
||||||
# Tip: Alternatively, you could link with the shared library:
|
|
||||||
|
# Tip 2: Alternatively, you could link with the shared libraries:
|
||||||
#set(CURSES_LIBRARY "/usr/lib/aarch64-linux-gnu/libncurses.so")
|
#set(CURSES_LIBRARY "/usr/lib/aarch64-linux-gnu/libncurses.so")
|
||||||
|
#set(TINFO_LIBRARY "/usr/lib/aarch64-linux-gnu/libtinfo.so")
|
||||||
|
|
||||||
#set(ZLIB_INCLUDE_DIR "/usr/include/")
|
#set(ZLIB_INCLUDE_DIR "/usr/include/")
|
||||||
#set(ZLIB_LIBRARY "/usr/lib64/libz.so")
|
#set(ZLIB_LIBRARY "/usr/lib64/libz.so")
|
||||||
|
@ -225,12 +227,14 @@ set(LIBXML2_LIBRARY "/usr/lib/aarch64-linux-gnu/libxml2.so")
|
||||||
set(PCRE2_INCLUDE_DIR "/usr/include/")
|
set(PCRE2_INCLUDE_DIR "/usr/include/")
|
||||||
set(PCRE2_LIBRARY "/usr/lib/aarch64-linux-gnu/libpcre2-8.so")
|
set(PCRE2_LIBRARY "/usr/lib/aarch64-linux-gnu/libpcre2-8.so")
|
||||||
|
|
||||||
set(CURSES_INCLUDE_DIR "/usr/include/")
|
set(NCURSES_INCLUDE_DIR "/usr/include/")
|
||||||
set(CURSES_LIBRARY "/usr/lib/aarch64-linux-gnu/libncurses.a;/usr/lib/aarch64-linux-gnu/libtinfo.a")
|
set(CURSES_LIBRARY "/usr/lib/aarch64-linux-gnu/libncurses.a")
|
||||||
# Tip: You may not need to also link with libtinfo.a, depending on what your distribution provides:
|
set(TINFO_LIBRARY "/usr/lib/aarch64-linux-gnu/libtinfo.a")
|
||||||
#set(CURSES_LIBRARY "/usr/lib/aarch64-linux-gnu/libncurses.a")
|
# Tip: You may not need to also link with libtinfo.a, depending on what your distribution provides.
|
||||||
# Tip: Alternatively, you could link with the shared library:
|
|
||||||
|
# Tip 2: Alternatively, you could link with the shared libraries:
|
||||||
#set(CURSES_LIBRARY "/usr/lib/aarch64-linux-gnu/libncurses.so")
|
#set(CURSES_LIBRARY "/usr/lib/aarch64-linux-gnu/libncurses.so")
|
||||||
|
#set(TINFO_LIBRARY "/usr/lib/aarch64-linux-gnu/libtinfo.so")
|
||||||
|
|
||||||
set(ZLIB_INCLUDE_DIR "/usr/include/")
|
set(ZLIB_INCLUDE_DIR "/usr/include/")
|
||||||
set(ZLIB_LIBRARY "/usr/lib/aarch64-linux-gnu/libz.so")
|
set(ZLIB_LIBRARY "/usr/lib/aarch64-linux-gnu/libz.so")
|
||||||
|
|
|
@ -675,6 +675,11 @@ and:
|
||||||
-D CURSES_LIBRARY="_filepath of curses library_"
|
-D CURSES_LIBRARY="_filepath of curses library_"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
and, if tinfo is separate from ncurses:
|
||||||
|
```sh
|
||||||
|
-D TINFO_LIBRARY="_filepath of tinfo library_"
|
||||||
|
```
|
||||||
|
|
||||||
### Bytecode Runtime
|
### Bytecode Runtime
|
||||||
|
|
||||||
Bytecode signatures are a type of executable plugin that provide extra
|
Bytecode signatures are a type of executable plugin that provide extra
|
||||||
|
|
18
Jenkinsfile
vendored
18
Jenkinsfile
vendored
|
@ -64,19 +64,6 @@ pipeline {
|
||||||
|
|
||||||
stages {
|
stages {
|
||||||
|
|
||||||
stage('GitGuardian Scan') {
|
|
||||||
environment {
|
|
||||||
GITGUARDIAN_API_KEY = credentials('gitguardian-token')
|
|
||||||
GITGUARDIAN_API_URL = 'https://gitguardian.cisco.com/'
|
|
||||||
}
|
|
||||||
agent { label "docker" }
|
|
||||||
steps {
|
|
||||||
withDockerContainer(args: "-i --entrypoint=''", image: 'gitguardian/ggshield:latest') {
|
|
||||||
sh 'ggshield secret scan ci'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stage('Generate Tarball') {
|
stage('Generate Tarball') {
|
||||||
steps {
|
steps {
|
||||||
cleanWs()
|
cleanWs()
|
||||||
|
@ -112,8 +99,9 @@ pipeline {
|
||||||
-D LIBXML2_LIBRARY="$HOME/.mussels/install/host-static/lib/libxml2.a" \
|
-D LIBXML2_LIBRARY="$HOME/.mussels/install/host-static/lib/libxml2.a" \
|
||||||
-D PCRE2_INCLUDE_DIR="$HOME/.mussels/install/host-static/include" \
|
-D PCRE2_INCLUDE_DIR="$HOME/.mussels/install/host-static/include" \
|
||||||
-D PCRE2_LIBRARY="$HOME/.mussels/install/host-static/lib/libpcre2-8.a" \
|
-D PCRE2_LIBRARY="$HOME/.mussels/install/host-static/lib/libpcre2-8.a" \
|
||||||
-D CURSES_INCLUDE_DIR="$HOME/.mussels/install/host-static/include" \
|
-D NCURSES_INCLUDE_DIR="$HOME/.mussels/install/host-static/include" \
|
||||||
-D CURSES_LIBRARY="$HOME/.mussels/install/host-static/lib/libncurses.a;$HOME/.mussels/install/host-static/lib/libtinfo.a" \
|
-D CURSES_LIBRARY="$HOME/.mussels/install/host-static/lib/libncurses.a" \
|
||||||
|
-D TINFO_LIBRARY="$HOME/.mussels/install/host-static/lib/libtinfo.a" \
|
||||||
-D ZLIB_INCLUDE_DIR="$HOME/.mussels/install/host-static/include" \
|
-D ZLIB_INCLUDE_DIR="$HOME/.mussels/install/host-static/include" \
|
||||||
-D ZLIB_LIBRARY="$HOME/.mussels/install/host-static/lib/libz.a" \
|
-D ZLIB_LIBRARY="$HOME/.mussels/install/host-static/lib/libz.a" \
|
||||||
-D LIBCHECK_INCLUDE_DIR="$HOME/.mussels/install/host-static/include" \
|
-D LIBCHECK_INCLUDE_DIR="$HOME/.mussels/install/host-static/include" \
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
install(DIRECTORY DESTINATION ${CVD_CERTS_DIRECTORY} COMPONENT programs)
|
install(DIRECTORY DESTINATION ${CVD_CERTS_DIRECTORY} COMPONENT programs)
|
||||||
install(
|
install(
|
||||||
FILES
|
FILES
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/clamav-beta.crt
|
${CMAKE_CURRENT_SOURCE_DIR}/clamav.crt
|
||||||
DESTINATION
|
DESTINATION
|
||||||
${CVD_CERTS_DIRECTORY}
|
${CVD_CERTS_DIRECTORY}
|
||||||
COMPONENT programs)
|
COMPONENT programs)
|
||||||
|
|
|
@ -1,31 +0,0 @@
|
||||||
-----BEGIN CERTIFICATE-----
|
|
||||||
MIIFWTCCA0ECFFGI/XH5m4TXcLToRREsv2+iSkhyMA0GCSqGSIb3DQEBCwUAMGkx
|
|
||||||
CzAJBgNVBAYTAlVTMQswCQYDVQQIDAJNRDEPMA0GA1UEBwwGTGF1cmVsMQ4wDAYD
|
|
||||||
VQQKDAVDaXNjbzEOMAwGA1UECwwFVGFsb3MxHDAaBgNVBAMME0NsYW1BViBCRVRB
|
|
||||||
IFJvb3QgQ0EwHhcNMjUwMzI2MjEzMTU2WhcNMjcwMzI2MjEzMTU2WjBpMQswCQYD
|
|
||||||
VQQGEwJVUzELMAkGA1UECAwCTUQxDzANBgNVBAcMBkxhdXJlbDEOMAwGA1UECgwF
|
|
||||||
Q2lzY28xDjAMBgNVBAsMBVRhbG9zMRwwGgYDVQQDDBNDbGFtQVYgQkVUQSBSb290
|
|
||||||
IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA8/tWT27KPBSFb7ER
|
|
||||||
c9jqJEhGXA0NNa/RBT5cumFsTm0253BXAJmIZa9EJTCyPuetGjQNKtOQ66VheL2D
|
|
||||||
2oyB3M7UIs1GP1epFu32eLDNzxPio6VV/Oge8Q7DVOsXtymS9jLNGmCAJ2gj+WuG
|
|
||||||
etV7laHuSFG02uwhef3yvfuvI4odRwEhSXiUt3J52siTnsetc9VLw6C4tAdtigBA
|
|
||||||
1oNx0pubPxAIXYNQeUeAZ8IyaUY+xtW/ekte8wFf4vbXXif1Fc4qA/tG0yGSIT2y
|
|
||||||
0SNrB1Wl0XTWQ63BStqY/Gqyyvr7BcZcPIcUIbIpmHFeYdp7WKfggQaOs3F5Fjvz
|
|
||||||
D17ZVRNkKCz0c3sLAQAOcB4gDHdbhNCQwY/w51ZkwYj1WdVeOsVLCq+itDD0lSiT
|
|
||||||
zrrchQbP3dytQTIiTX3V413QVPv7Tc6sZZELA3CiOTgrPj5TGWPVmhzCXOnllGZB
|
|
||||||
2gloHz8kxU1Uh/XzT8Qgi3CSZK0kweunIRYLmHGhdPcGeELK1SdJt7InFWzoUPLS
|
|
||||||
+sWJ+7/hqz5qeNJjTQTOZ+QYxvVlSU+fpUr2ovN4lVwzlr9jBZMb+vIlP7nhNpx3
|
|
||||||
8JL+ARc9E8k1vnxMA5YN1cDvkebi236vazXnoNunGhk4oHuBGXPvLzM1IGFbh3qC
|
|
||||||
bV9q343HnKa8PjouGY32+7gW1QUCAwEAATANBgkqhkiG9w0BAQsFAAOCAgEAxw7M
|
|
||||||
RwgCrnebt9yEUmzE+/Z1UHl+MZsLUiyoraQXgx/gtJeD34H+MMIivxt/j260aser
|
|
||||||
/nPF0WQ7up6WuQ6tEdU0KPH18g4cCL8H8p/SFYSw0u02NB1d69NUvhR7TLwS1yKQ
|
|
||||||
AdiQH5Vw7y18rZKGoMiEvKPDnfkTwQY9EAdAcFxjwlWroB437MFmXe7wz3uQdB+i
|
|
||||||
A5g6lKtkvYcUQddIKfCsNVzRN2q4BjQq2EdwUSC+Z12baaTAx+BUSppvvhD7t9Fa
|
|
||||||
CNDAJkaVGFvo8CnuOkNCgDMnXLMP95HhwTzRLJIEfGu8uDKRe0yJfBnNAZyHiUdf
|
|
||||||
qNhtkjfdnNT2ZzHaRuAbc+6bm8NAzPH9dkdg5RxTvdAEZfRzMythLso47PX94mlt
|
|
||||||
7SjZnIvArJt4TjoQ5K6JnX9CmEJeXBuVbNfiCnu11MitrfVV8BWpBh4gIP5x4kM4
|
|
||||||
qyFle7x2jDaC9Nc14QpOsNcmFI0i8itXwqKTaqnX4r05w0IIHu6RbgzXyJLSGMi0
|
|
||||||
Bd/OoRMlH6aAxOD3W8PR18TkR7wt5++qMEC+hvpTIBfqDzM6q/l1Gv1/xzKtDiFL
|
|
||||||
9ZmIM79osXAOPMn/dNAh4hVURBl2n7/69FSRzQbVIBGt2YYlWV9HVfOXquuYJ3py
|
|
||||||
pOQCrNNrFjEMFifHqO2ktkn7c8Tsw4dFVnIhKFU=
|
|
||||||
-----END CERTIFICATE-----
|
|
32
certs/clamav.crt
Executable file
32
certs/clamav.crt
Executable file
|
@ -0,0 +1,32 @@
|
||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIFhTCCA22gAwIBAgIJBJPyuFHF1b7RMA0GCSqGSIb3DQEBDQUAMF8xDjAMBgNV
|
||||||
|
BAsTBUFyYm9yMQ4wDAYDVQQKEwVDaXNjbzE9MDsGA1UEAxM0Q2lzY28gU29mdHdh
|
||||||
|
cmUgSWRlbnRpdHkgUm9vdCBDQSBSU0EgNDA5NiBTSEE1MTIgMjA5OTAgFw0yNDAx
|
||||||
|
MjQxODQ1MjVaGA8yMDk5MDEyNDE4NDUyNVowXzEOMAwGA1UECxMFQXJib3IxDjAM
|
||||||
|
BgNVBAoTBUNpc2NvMT0wOwYDVQQDEzRDaXNjbyBTb2Z0d2FyZSBJZGVudGl0eSBS
|
||||||
|
b290IENBIFJTQSA0MDk2IFNIQTUxMiAyMDk5MIICIjANBgkqhkiG9w0BAQEFAAOC
|
||||||
|
Ag8AMIICCgKCAgEA14hoPbzqZxPr8Wqpq2H+tOib+DkQP80mUP6zAw3uu+eNygd+
|
||||||
|
jOBCenO6B7sp1sqCRT8QBQWQxNHVeVfMQN1vjMrqEMNh/eflVtOGy32UbkuQrVzj
|
||||||
|
2H+G1PtjeMQKa26LD8XPDUIOpj9rzPdjKFFfz13tm21gNIiVSTI34T5BS5BNEQj1
|
||||||
|
b+VQg+0kbANCOOTiTh+H/gxhpXRv8F3VNUrrPxA7a3WF5jhZZoPBns1LuBDW0fQ0
|
||||||
|
av6q/uEWtfxMdSNsAxYWVhO90Nx4khOISA1Fs1h1klGsee5XZkLKdUWedZQzbUz1
|
||||||
|
f7VPRxX+ddcK0Js2VPvxemMf2WaTbkrEi62y/cOaxqDs2xDTWEXrgOYYEfQ+RoeY
|
||||||
|
pbzBCaErqZvCeOgrnXFSHSyyd9+dTOxJuypBH+AWKtmkQMQQ7RQJSkGvrP9NgRxD
|
||||||
|
MXb1U4kpVn7kEEhv6telV9E8R635Zm4h/H9FQyc2LrLOuL5UPewMMWt8HqPbs2Xc
|
||||||
|
n1kTLvpEDciDJDRvu4XuBsjgQMA0rlt5BHAmZdGO5Dq4+ARWAYrzN9+M0dK+0phT
|
||||||
|
T9OOHItIL6wXcIiYLZBJlHfiemCByIcBBEYaRwdt3VP9tTl0F370StI2t1RMDPgt
|
||||||
|
xHcsYqN09QG/tWzwr/yNckFhVs/+UGQWslv2/W6eiKge5REUFuxT6i7V6oUCAwEA
|
||||||
|
AaNCMEAwDgYDVR0PAQH/BAQDAgEGMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYE
|
||||||
|
FLd8Wz4X/JJ6Oi/+znsT0DTPuju8MA0GCSqGSIb3DQEBDQUAA4ICAQCZEut7iqp8
|
||||||
|
39u7CHD8zMrvOMmUKtJ7G1MrhkJfdyek8g7ArG74bgcxM3ptwDusdFgKh/mmCj/m
|
||||||
|
FU6TNjsufZ9hAyOE16ZtGflkOrRlihPQThDdGCxQjRsLVQa9S0IDkM1v1ZqvIMEc
|
||||||
|
PJOj3rhvkIJVjpHc0AZQP/TnaT/7dKD1wFOSNYwzdvE2HKVNA8XbeS9TNpHqYPvE
|
||||||
|
2gX6vQ7Pdn9DIF6YOmOuBobmaD1G7WbDz5Kvz5e3FdkzR+K3sGW4Qsr3OLt25dQS
|
||||||
|
H+x7X06fihUxhEgRJJp2cPKABSKVR2hoyzKNEbzgtV25gH7lr+EHA6CQYltkVpyM
|
||||||
|
4v1+PdX1EGY0+rAO+NsRwa6ndFteofJLh9PbvxHp0jGWnT1KF4lhmEyyka9JKbqT
|
||||||
|
yiyGzDsw/YA9NxiAsp/Ex8aYXX1/SeM/kb6dp7tytsHewwflns1jfGqRVyrXQ41x
|
||||||
|
CmmSioBvtZiry8BJTa8xIUWEsBL1pTl2RZrPDAw/qD10K2XJfh5HYFSkIppoIO+9
|
||||||
|
0wN8TYcXbyY+JnU/g32AvkmA3o8lotK6nbwuf7MAFdtPHMA4F8mPM3jADc1uGu9O
|
||||||
|
YweaA1c+P5KEOyr325cgsT04x4oeyvP3c3XMLpDpSgbzhfc9WyLYCf3R3jHlst1A
|
||||||
|
KaDwBk2xoE3knxihYjbcRfjaaYdUkWY4mg==
|
||||||
|
-----END CERTIFICATE-----
|
|
@ -367,9 +367,6 @@
|
||||||
/* yara sources are compiled in */
|
/* yara sources are compiled in */
|
||||||
#define HAVE_YARA 1
|
#define HAVE_YARA 1
|
||||||
|
|
||||||
/* For internal use only - DO NOT DEFINE */
|
|
||||||
#cmakedefine HAVE__INTERNAL__SHA_COLLECT 1
|
|
||||||
|
|
||||||
/* Define as const if the declaration of iconv() needs const. */
|
/* Define as const if the declaration of iconv() needs const. */
|
||||||
#cmakedefine ICONV_CONST @ICONV_CONST@
|
#cmakedefine ICONV_CONST @ICONV_CONST@
|
||||||
|
|
||||||
|
|
|
@ -398,24 +398,16 @@ int main(int argc, char *argv[])
|
||||||
fprintf(stderr, "Out of memory\n");
|
fprintf(stderr, "Out of memory\n");
|
||||||
exit(3);
|
exit(3);
|
||||||
}
|
}
|
||||||
ctx->ctx = &cctx;
|
ctx->ctx = &cctx;
|
||||||
cctx.engine = engine;
|
cctx.engine = engine;
|
||||||
cctx.evidence = evidence_new();
|
|
||||||
|
|
||||||
cctx.recursion_stack_size = cctx.engine->max_recursion_level;
|
cctx.recursion_stack_size = cctx.engine->max_recursion_level;
|
||||||
cctx.recursion_stack = calloc(sizeof(recursion_level_t), cctx.recursion_stack_size);
|
cctx.recursion_stack = calloc(sizeof(cli_scan_layer_t), cctx.recursion_stack_size);
|
||||||
if (!cctx.recursion_stack) {
|
if (!cctx.recursion_stack) {
|
||||||
fprintf(stderr, "Out of memory\n");
|
fprintf(stderr, "Out of memory\n");
|
||||||
exit(3);
|
exit(3);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ctx was memset, so recursion_level starts at 0.
|
|
||||||
cctx.recursion_stack[cctx.recursion_level].fmap = map;
|
|
||||||
cctx.recursion_stack[cctx.recursion_level].type = CL_TYPE_ANY; /* ANY for the top level, because we don't yet know the type. */
|
|
||||||
cctx.recursion_stack[cctx.recursion_level].size = map->len;
|
|
||||||
|
|
||||||
cctx.fmap = cctx.recursion_stack[cctx.recursion_level].fmap;
|
|
||||||
|
|
||||||
memset(&dbg_state, 0, sizeof(dbg_state));
|
memset(&dbg_state, 0, sizeof(dbg_state));
|
||||||
dbg_state.file = "<libclamav>";
|
dbg_state.file = "<libclamav>";
|
||||||
dbg_state.line = 0;
|
dbg_state.line = 0;
|
||||||
|
@ -453,11 +445,18 @@ int main(int argc, char *argv[])
|
||||||
optfree(opts);
|
optfree(opts);
|
||||||
exit(5);
|
exit(5);
|
||||||
}
|
}
|
||||||
map = fmap(fd, 0, 0, opt->strarg);
|
|
||||||
|
map = fmap_new(fd, 0, 0, opt->strarg, opt->strarg);
|
||||||
if (!map) {
|
if (!map) {
|
||||||
fprintf(stderr, "Unable to map input file %s\n", opt->strarg);
|
fprintf(stderr, "Unable to map input file %s\n", opt->strarg);
|
||||||
exit(5);
|
exit(5);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ctx was memset, so recursion_level starts at 0.
|
||||||
|
cctx.recursion_stack[cctx.recursion_level].fmap = map;
|
||||||
|
cctx.recursion_stack[cctx.recursion_level].type = CL_TYPE_ANY; /* ANY for the top level, because we don't yet know the type. */
|
||||||
|
cctx.recursion_stack[cctx.recursion_level].size = map->len;
|
||||||
|
|
||||||
rc = cli_bytecode_context_setfile(ctx, map);
|
rc = cli_bytecode_context_setfile(ctx, map);
|
||||||
if (rc != CL_SUCCESS) {
|
if (rc != CL_SUCCESS) {
|
||||||
fprintf(stderr, "Unable to set file %s: %s\n", opt->strarg, cl_strerror(rc));
|
fprintf(stderr, "Unable to set file %s: %s\n", opt->strarg, cl_strerror(rc));
|
||||||
|
@ -465,10 +464,15 @@ int main(int argc, char *argv[])
|
||||||
exit(5);
|
exit(5);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* for testing */
|
/* for testing */
|
||||||
ctx->hooks.match_counts = deadbeefcounts;
|
ctx->hooks.match_counts = deadbeefcounts;
|
||||||
ctx->hooks.match_offsets = deadbeefcounts;
|
ctx->hooks.match_offsets = deadbeefcounts;
|
||||||
rc = cli_bytecode_run(&bcs, bc, ctx);
|
|
||||||
|
/*
|
||||||
|
* Run the bytecode.
|
||||||
|
*/
|
||||||
|
rc = cli_bytecode_run(&bcs, bc, ctx);
|
||||||
if (rc != CL_SUCCESS) {
|
if (rc != CL_SUCCESS) {
|
||||||
fprintf(stderr, "Unable to run bytecode: %s\n", cl_strerror(rc));
|
fprintf(stderr, "Unable to run bytecode: %s\n", cl_strerror(rc));
|
||||||
} else {
|
} else {
|
||||||
|
@ -479,12 +483,15 @@ int main(int argc, char *argv[])
|
||||||
if (debug_flag)
|
if (debug_flag)
|
||||||
printf("[clambc] Bytecode returned: 0x%llx\n", (long long)v);
|
printf("[clambc] Bytecode returned: 0x%llx\n", (long long)v);
|
||||||
}
|
}
|
||||||
|
|
||||||
cli_bytecode_context_destroy(ctx);
|
cli_bytecode_context_destroy(ctx);
|
||||||
if (map)
|
if (map)
|
||||||
funmap(map);
|
fmap_free(map);
|
||||||
cl_engine_free(engine);
|
if (cctx.recursion_stack[cctx.recursion_level].evidence) {
|
||||||
|
evidence_free(cctx.recursion_stack[cctx.recursion_level].evidence);
|
||||||
|
}
|
||||||
free(cctx.recursion_stack);
|
free(cctx.recursion_stack);
|
||||||
evidence_free(cctx.evidence);
|
cl_engine_free(engine);
|
||||||
}
|
}
|
||||||
cli_bytecode_destroy(bc);
|
cli_bytecode_destroy(bc);
|
||||||
cli_bytecode_done(&bcs);
|
cli_bytecode_done(&bcs);
|
||||||
|
|
|
@ -228,7 +228,7 @@ static void print_platform(struct cli_environment *env)
|
||||||
|
|
||||||
printf("OS: " TARGET_OS_TYPE ", ARCH: " TARGET_ARCH_TYPE ", CPU: " TARGET_CPU_TYPE "\n");
|
printf("OS: " TARGET_OS_TYPE ", ARCH: " TARGET_ARCH_TYPE ", CPU: " TARGET_CPU_TYPE "\n");
|
||||||
|
|
||||||
#ifdef C_LINUX
|
#if defined(C_LINUX) || defined(C_GNU_HURD)
|
||||||
if (!access("/usr/bin/lsb_release", X_OK)) {
|
if (!access("/usr/bin/lsb_release", X_OK)) {
|
||||||
fputs("Full OS version: ", stdout);
|
fputs("Full OS version: ", stdout);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
|
|
|
@ -51,7 +51,7 @@
|
||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef C_LINUX
|
#if defined(C_LINUX) || defined(__GLIBC__)
|
||||||
#include <sys/resource.h>
|
#include <sys/resource.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -150,7 +150,7 @@ int main(int argc, char **argv)
|
||||||
struct sigaction sa;
|
struct sigaction sa;
|
||||||
int dropPrivRet = 0;
|
int dropPrivRet = 0;
|
||||||
#endif
|
#endif
|
||||||
#if defined(C_LINUX) || (defined(RLIMIT_DATA) && defined(C_BSD))
|
#if defined(C_LINUX) || defined(__GLIBC__) || (defined(RLIMIT_DATA) && defined(C_BSD))
|
||||||
struct rlimit rlim;
|
struct rlimit rlim;
|
||||||
#endif
|
#endif
|
||||||
time_t currtime;
|
time_t currtime;
|
||||||
|
@ -201,7 +201,7 @@ int main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (optget(opts, "debug")->enabled) {
|
if (optget(opts, "debug")->enabled) {
|
||||||
#if defined(C_LINUX)
|
#if defined(C_LINUX) || defined(__GLIBC__)
|
||||||
/* njh@bandsman.co.uk: create a dump if needed */
|
/* njh@bandsman.co.uk: create a dump if needed */
|
||||||
rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY;
|
rlim.rlim_cur = rlim.rlim_max = RLIM_INFINITY;
|
||||||
if (setrlimit(RLIMIT_CORE, &rlim) < 0)
|
if (setrlimit(RLIMIT_CORE, &rlim) < 0)
|
||||||
|
@ -616,8 +616,12 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
cl_engine_set_clcb_virus_found(engine, clamd_virus_found_cb);
|
cl_engine_set_clcb_virus_found(engine, clamd_virus_found_cb);
|
||||||
|
|
||||||
if (optget(opts, "LeaveTemporaryFiles")->enabled)
|
if (optget(opts, "LeaveTemporaryFiles")->enabled) {
|
||||||
|
/* Set the engine to keep temporary files */
|
||||||
cl_engine_set_num(engine, CL_ENGINE_KEEPTMP, 1);
|
cl_engine_set_num(engine, CL_ENGINE_KEEPTMP, 1);
|
||||||
|
/* Also set the engine to create temporary directory structure */
|
||||||
|
cl_engine_set_num(engine, CL_ENGINE_TMPDIR_RECURSION, 1);
|
||||||
|
}
|
||||||
|
|
||||||
if (optget(opts, "ForceToDisk")->enabled)
|
if (optget(opts, "ForceToDisk")->enabled)
|
||||||
cl_engine_set_num(engine, CL_ENGINE_FORCETODISK, 1);
|
cl_engine_set_num(engine, CL_ENGINE_FORCETODISK, 1);
|
||||||
|
@ -705,6 +709,12 @@ int main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (optget(opts, "FIPSCryptoHashLimits")->enabled) {
|
||||||
|
dboptions |= CL_DB_FIPS_LIMITS;
|
||||||
|
cl_engine_set_num(engine, CL_ENGINE_FIPS_LIMITS, 1);
|
||||||
|
logg(LOGG_INFO_NF, "FIPS crypto hash limits enabled.\n");
|
||||||
|
}
|
||||||
|
|
||||||
if ((ret = cl_load(dbdir, engine, &sigs, dboptions))) {
|
if ((ret = cl_load(dbdir, engine, &sigs, dboptions))) {
|
||||||
logg(LOGG_ERROR, "%s\n", cl_strerror(ret));
|
logg(LOGG_ERROR, "%s\n", cl_strerror(ret));
|
||||||
ret = 1;
|
ret = 1;
|
||||||
|
|
|
@ -94,7 +94,7 @@ void msg_callback(enum cl_msg severity, const char *fullmsg, const char *msg, vo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void hash_callback(int fd, unsigned long long size, const unsigned char *md5, const char *virname, void *ctx)
|
void hash_callback(int fd, unsigned long long size, const char *md5, const char *virname, void *ctx)
|
||||||
{
|
{
|
||||||
struct cb_context *c = ctx;
|
struct cb_context *c = ctx;
|
||||||
UNUSEDPARAM(fd);
|
UNUSEDPARAM(fd);
|
||||||
|
@ -103,8 +103,8 @@ void hash_callback(int fd, unsigned long long size, const unsigned char *md5, co
|
||||||
if (!c)
|
if (!c)
|
||||||
return;
|
return;
|
||||||
c->virsize = size;
|
c->virsize = size;
|
||||||
strncpy(c->virhash, (const char *)md5, 32);
|
strncpy(c->virhash, md5, MD5_HASH_SIZE * 2);
|
||||||
c->virhash[32] = '\0';
|
c->virhash[MD5_HASH_SIZE * 2] = '\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
void clamd_virus_found_cb(int fd, const char *virname, void *ctx)
|
void clamd_virus_found_cb(int fd, const char *virname, void *ctx)
|
||||||
|
|
|
@ -69,7 +69,7 @@ cl_error_t scanfd(const client_conn_t *conn, unsigned long int *scanned, const s
|
||||||
int scanstream(int odesc, unsigned long int *scanned, const struct cl_engine *engine, struct cl_scan_options *options, const struct optstruct *opts, char term);
|
int scanstream(int odesc, unsigned long int *scanned, const struct cl_engine *engine, struct cl_scan_options *options, const struct optstruct *opts, char term);
|
||||||
cl_error_t scan_callback(STATBUF *sb, char *filename, const char *msg, enum cli_ftw_reason reason, struct cli_ftw_cbdata *data);
|
cl_error_t scan_callback(STATBUF *sb, char *filename, const char *msg, enum cli_ftw_reason reason, struct cli_ftw_cbdata *data);
|
||||||
int scan_pathchk(const char *path, struct cli_ftw_cbdata *data);
|
int scan_pathchk(const char *path, struct cli_ftw_cbdata *data);
|
||||||
void hash_callback(int fd, unsigned long long size, const unsigned char *md5, const char *virname, void *ctx);
|
void hash_callback(int fd, unsigned long long size, const char *md5, const char *virname, void *ctx);
|
||||||
void msg_callback(enum cl_msg severity, const char *fullmsg, const char *msg, void *ctx);
|
void msg_callback(enum cl_msg severity, const char *fullmsg, const char *msg, void *ctx);
|
||||||
void clamd_virus_found_cb(int fd, const char *virname, void *context);
|
void clamd_virus_found_cb(int fd, const char *virname, void *context);
|
||||||
|
|
||||||
|
|
|
@ -499,18 +499,19 @@ struct acceptdata {
|
||||||
struct fd_data fds;
|
struct fd_data fds;
|
||||||
struct fd_data recv_fds;
|
struct fd_data recv_fds;
|
||||||
pthread_cond_t cond_nfds;
|
pthread_cond_t cond_nfds;
|
||||||
|
unsigned initial_fds;
|
||||||
int max_queue;
|
int max_queue;
|
||||||
int commandtimeout;
|
int commandtimeout;
|
||||||
int syncpipe_wake_recv[2];
|
int syncpipe_wake_recv[2];
|
||||||
int syncpipe_wake_accept[2];
|
int syncpipe_wake_accept[2];
|
||||||
};
|
};
|
||||||
|
|
||||||
#define ACCEPTDATA_INIT(mutex1, mutex2) \
|
#define ACCEPTDATA_INIT(mutex1, mutex2) \
|
||||||
{ \
|
{ \
|
||||||
FDS_INIT(mutex1), FDS_INIT(mutex2), PTHREAD_COND_INITIALIZER, 0, 0, {-1, -1}, \
|
FDS_INIT(mutex1), FDS_INIT(mutex2), PTHREAD_COND_INITIALIZER, 0, 0, 0, {-1, -1}, \
|
||||||
{ \
|
{ \
|
||||||
-1, -1 \
|
-1, -1 \
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
static void *acceptloop_th(void *arg)
|
static void *acceptloop_th(void *arg)
|
||||||
|
@ -646,7 +647,7 @@ static void *acceptloop_th(void *arg)
|
||||||
|
|
||||||
if (sd_listen_fds(0) == 0) {
|
if (sd_listen_fds(0) == 0) {
|
||||||
/* only close the sockets, when not using systemd socket activation */
|
/* only close the sockets, when not using systemd socket activation */
|
||||||
for (i = 0; i < fds->nfds; i++) {
|
for (i = data->initial_fds; i < fds->nfds; i++) {
|
||||||
if (fds->buf[i].fd == -1)
|
if (fds->buf[i].fd == -1)
|
||||||
continue;
|
continue;
|
||||||
logg(LOGG_DEBUG_NV, "Shutdown: closed fd %d\n", fds->buf[i].fd);
|
logg(LOGG_DEBUG_NV, "Shutdown: closed fd %d\n", fds->buf[i].fd);
|
||||||
|
@ -923,6 +924,9 @@ int recvloop(int *socketds, unsigned nsockets, struct cl_engine *engine, unsigne
|
||||||
unsigned int selfchk;
|
unsigned int selfchk;
|
||||||
threadpool_t *thr_pool;
|
threadpool_t *thr_pool;
|
||||||
|
|
||||||
|
// Initial sockets will be closed in clamd.c
|
||||||
|
acceptdata.initial_fds = nsockets;
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
memset(&sigact, 0, sizeof(struct sigaction));
|
memset(&sigact, 0, sizeof(struct sigaction));
|
||||||
#endif
|
#endif
|
||||||
|
@ -1379,11 +1383,6 @@ int recvloop(int *socketds, unsigned nsockets, struct cl_engine *engine, unsigne
|
||||||
options.heuristic |= CL_SCAN_HEURISTIC_STRUCTURED_SSN_STRIPPED;
|
options.heuristic |= CL_SCAN_HEURISTIC_STRUCTURED_SSN_STRIPPED;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE__INTERNAL__SHA_COLLECT
|
|
||||||
if (optget(opts, "DevCollectHashes")->enabled)
|
|
||||||
options.dev |= CL_SCAN_DEV_COLLECT_SHA;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (optget(opts, "GenerateMetadataJson")->enabled) {
|
if (optget(opts, "GenerateMetadataJson")->enabled) {
|
||||||
options.general |= CL_SCAN_GENERAL_COLLECT_METADATA;
|
options.general |= CL_SCAN_GENERAL_COLLECT_METADATA;
|
||||||
}
|
}
|
||||||
|
@ -1396,6 +1395,10 @@ int recvloop(int *socketds, unsigned nsockets, struct cl_engine *engine, unsigne
|
||||||
options.general |= CL_SCAN_GENERAL_STORE_PDF_URIS;
|
options.general |= CL_SCAN_GENERAL_STORE_PDF_URIS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (optget(opts, "JsonStoreExtraHashes")->enabled) {
|
||||||
|
options.general |= CL_SCAN_GENERAL_STORE_EXTRA_HASHES;
|
||||||
|
}
|
||||||
|
|
||||||
selfchk = optget(opts, "SelfCheck")->numarg;
|
selfchk = optget(opts, "SelfCheck")->numarg;
|
||||||
if (!selfchk) {
|
if (!selfchk) {
|
||||||
logg(LOGG_INFO, "Self checking disabled.\n");
|
logg(LOGG_INFO, "Self checking disabled.\n");
|
||||||
|
|
|
@ -175,7 +175,7 @@ int16_t ping_clamd(const struct optstruct *opts)
|
||||||
char *errchk = NULL;
|
char *errchk = NULL;
|
||||||
uint64_t i = 0;
|
uint64_t i = 0;
|
||||||
const struct optstruct *opt = NULL;
|
const struct optstruct *opt = NULL;
|
||||||
int64_t sockd;
|
int64_t sockd = -1;
|
||||||
struct RCVLN rcv;
|
struct RCVLN rcv;
|
||||||
uint16_t ret = 0;
|
uint16_t ret = 0;
|
||||||
|
|
||||||
|
@ -227,6 +227,7 @@ int16_t ping_clamd(const struct optstruct *opts)
|
||||||
if (sendln(sockd, zPING, sizeof(zPING))) {
|
if (sendln(sockd, zPING, sizeof(zPING))) {
|
||||||
logg(LOGG_DEBUG, "PING failed...\n");
|
logg(LOGG_DEBUG, "PING failed...\n");
|
||||||
closesocket(sockd);
|
closesocket(sockd);
|
||||||
|
sockd = -1;
|
||||||
} else {
|
} else {
|
||||||
if (!optget(opts, "wait")->enabled) {
|
if (!optget(opts, "wait")->enabled) {
|
||||||
logg(LOGG_INFO, "PONG\n");
|
logg(LOGG_INFO, "PONG\n");
|
||||||
|
@ -262,6 +263,9 @@ int16_t ping_clamd(const struct optstruct *opts)
|
||||||
}
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
if (sockd >= 0) {
|
||||||
|
closesocket(sockd);
|
||||||
|
}
|
||||||
if (attempt_str) {
|
if (attempt_str) {
|
||||||
free(attempt_str);
|
free(attempt_str);
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,10 +60,22 @@ struct s_info info;
|
||||||
short recursion = 0, bell = 0;
|
short recursion = 0, bell = 0;
|
||||||
short printinfected = 0, printclean = 1;
|
short printinfected = 0, printclean = 1;
|
||||||
|
|
||||||
|
static void loggBytes(uint64_t bytes)
|
||||||
|
{
|
||||||
|
if (bytes >= (1024 * 1024 * 1024)) {
|
||||||
|
logg(LOGG_INFO, "%.02f GiB", bytes / (double)(1024 * 1024 * 1024));
|
||||||
|
} else if (bytes >= (1024 * 1024)) {
|
||||||
|
logg(LOGG_INFO, "%.02f MiB", bytes / (double)(1024 * 1024));
|
||||||
|
} else if (bytes >= 1024) {
|
||||||
|
logg(LOGG_INFO, "%.02f KiB", bytes / (double)(1024));
|
||||||
|
} else {
|
||||||
|
logg(LOGG_INFO, "%" PRIu64 " B", bytes);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int ds, dms, ret;
|
int ds, dms, ret;
|
||||||
double mb, rmb;
|
|
||||||
struct timeval t1, t2;
|
struct timeval t1, t2;
|
||||||
time_t date_start, date_end;
|
time_t date_start, date_end;
|
||||||
|
|
||||||
|
@ -195,10 +207,15 @@ int main(int argc, char **argv)
|
||||||
if (notmoved) {
|
if (notmoved) {
|
||||||
logg(LOGG_INFO, "Not %s: %u\n", optget(opts, "copy")->enabled ? "moved" : "copied", notmoved);
|
logg(LOGG_INFO, "Not %s: %u\n", optget(opts, "copy")->enabled ? "moved" : "copied", notmoved);
|
||||||
}
|
}
|
||||||
mb = info.blocks * (CL_COUNT_PRECISION / 1024) / 1024.0;
|
|
||||||
logg(LOGG_INFO, "Data scanned: %2.2lf MB\n", mb);
|
logg(LOGG_INFO, "Data scanned: ");
|
||||||
rmb = info.rblocks * (CL_COUNT_PRECISION / 1024) / 1024.0;
|
loggBytes(info.bytes_scanned);
|
||||||
logg(LOGG_INFO, "Data read: %2.2lf MB (ratio %.2f:1)\n", rmb, info.rblocks ? (double)info.blocks / (double)info.rblocks : 0);
|
logg(LOGG_INFO, "\n");
|
||||||
|
|
||||||
|
logg(LOGG_INFO, "Data read: ");
|
||||||
|
loggBytes(info.bytes_read);
|
||||||
|
logg(LOGG_INFO, " (ratio %.2f:1)\n", info.bytes_read ? (double)info.bytes_scanned / (double)info.bytes_read : 0);
|
||||||
|
|
||||||
logg(LOGG_INFO, "Time: %u.%3.3u sec (%u m %u s)\n", ds, dms / 1000, ds / 60, ds % 60);
|
logg(LOGG_INFO, "Time: %u.%3.3u sec (%u m %u s)\n", ds, dms / 1000, ds / 60, ds % 60);
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
@ -238,117 +255,135 @@ void help(void)
|
||||||
mprintf(LOGG_INFO, "\n");
|
mprintf(LOGG_INFO, "\n");
|
||||||
mprintf(LOGG_INFO, " clamscan [options] [file/directory/-]\n");
|
mprintf(LOGG_INFO, " clamscan [options] [file/directory/-]\n");
|
||||||
mprintf(LOGG_INFO, "\n");
|
mprintf(LOGG_INFO, "\n");
|
||||||
mprintf(LOGG_INFO, " --help -h Show this help\n");
|
mprintf(LOGG_INFO, " --help -h Show this help.\n");
|
||||||
mprintf(LOGG_INFO, " --version -V Print version number\n");
|
mprintf(LOGG_INFO, " --version -V Print version number.\n");
|
||||||
mprintf(LOGG_INFO, " --verbose -v Be verbose\n");
|
mprintf(LOGG_INFO, " --verbose -v Be verbose.\n");
|
||||||
mprintf(LOGG_INFO, " --archive-verbose -a Show filenames inside scanned archives\n");
|
mprintf(LOGG_INFO, " --archive-verbose -a Show filenames inside scanned archives.\n");
|
||||||
mprintf(LOGG_INFO, " --debug Enable libclamav's debug messages\n");
|
mprintf(LOGG_INFO, " --debug Enable libclamav's debug messages.\n");
|
||||||
mprintf(LOGG_INFO, " --quiet Only output error messages\n");
|
mprintf(LOGG_INFO, " --quiet Only output error messages.\n");
|
||||||
mprintf(LOGG_INFO, " --stdout Write to stdout instead of stderr. Does not affect 'debug' messages.\n");
|
mprintf(LOGG_INFO, " --stdout Write to stdout instead of stderr. Does not affect 'debug' messages.\n");
|
||||||
mprintf(LOGG_INFO, " --no-summary Disable summary at end of scanning\n");
|
mprintf(LOGG_INFO, " --no-summary Disable summary at end of scanning.\n");
|
||||||
mprintf(LOGG_INFO, " --infected -i Only print infected files\n");
|
mprintf(LOGG_INFO, " --infected -i Only print infected files.\n");
|
||||||
mprintf(LOGG_INFO, " --suppress-ok-results -o Skip printing OK files\n");
|
mprintf(LOGG_INFO, " --suppress-ok-results -o Skip printing OK files.\n");
|
||||||
mprintf(LOGG_INFO, " --bell Sound bell on virus detection\n");
|
mprintf(LOGG_INFO, " --bell Sound bell on virus detection.\n");
|
||||||
mprintf(LOGG_INFO, "\n");
|
mprintf(LOGG_INFO, "\n");
|
||||||
mprintf(LOGG_INFO, " --tempdir=DIRECTORY Create temporary files in DIRECTORY\n");
|
mprintf(LOGG_INFO, " --tempdir=DIRECTORY Create temporary files in DIRECTORY.\n");
|
||||||
mprintf(LOGG_INFO, " --leave-temps[=yes/no(*)] Do not remove temporary files\n");
|
mprintf(LOGG_INFO, " --leave-temps[=yes/no(*)] Do not remove temporary files.\n");
|
||||||
mprintf(LOGG_INFO, " --force-to-disk[=yes/no(*)] Create temporary files for nested file scans that would otherwise be in-memory only\n");
|
mprintf(LOGG_INFO, " --force-to-disk[=yes/no(*)] Create temporary files for nested file scans that would otherwise be in-memory only.\n");
|
||||||
mprintf(LOGG_INFO, " --gen-json[=yes/no(*)] Generate JSON metadata for the scanned file(s). For testing & development use ONLY.\n");
|
mprintf(LOGG_INFO, " --gen-json[=yes/no(*)] Generate JSON metadata for the scanned file(s). For testing & development use ONLY.\n");
|
||||||
mprintf(LOGG_INFO, " JSON will be printed if --debug is enabled.\n");
|
mprintf(LOGG_INFO, " JSON will be printed if --debug is enabled.\n");
|
||||||
mprintf(LOGG_INFO, " A JSON file will dropped to the temp directory if --leave-temps is enabled.\n");
|
mprintf(LOGG_INFO, " A JSON file will dropped to the temp directory if --leave-temps is enabled.\n");
|
||||||
mprintf(LOGG_INFO, " --json-store-html-uris[=yes(*)/no] Store html URIs in metadata.\n");
|
mprintf(LOGG_INFO, " --json-store-html-uris[=yes(*)/no] Store html URIs in metadata.\n");
|
||||||
mprintf(LOGG_INFO, " URLs will be written to the metadata.json file in an array called 'URIs'\n");
|
mprintf(LOGG_INFO, " URIs will be written to the metadata.json file in an array called 'URIs'.\n");
|
||||||
mprintf(LOGG_INFO, " --json-store-pdf-uris[=yes(*)/no] Store pdf URIs in metadata.\n");
|
mprintf(LOGG_INFO, " --json-store-pdf-uris[=yes(*)/no] Store pdf URIs in metadata.\n");
|
||||||
mprintf(LOGG_INFO, " URLs will be written to the metadata.json file in an array called 'URIs'\n");
|
mprintf(LOGG_INFO, " URIs will be written to the metadata.json file in an array called 'URIs'.\n");
|
||||||
mprintf(LOGG_INFO, " --database=FILE/DIR -d FILE/DIR Load virus database from FILE or load all supported db files from DIR\n");
|
mprintf(LOGG_INFO, " --json-store-extra-hashes[=yes(*)/no] Store md5 and sha1 in addition to sha2-256 in metadata.\n");
|
||||||
mprintf(LOGG_INFO, " --official-db-only[=yes/no(*)] Only load official signatures\n");
|
mprintf(LOGG_INFO, " --database=FILE/DIR -d FILE/DIR Load virus database from FILE or load all supported db files from DIR.\n");
|
||||||
|
mprintf(LOGG_INFO, " --official-db-only[=yes/no(*)] Only load official signatures.\n");
|
||||||
mprintf(LOGG_INFO, " --fail-if-cvd-older-than=days Return with a nonzero error code if virus database outdated.\n");
|
mprintf(LOGG_INFO, " --fail-if-cvd-older-than=days Return with a nonzero error code if virus database outdated.\n");
|
||||||
mprintf(LOGG_INFO, " --log=FILE -l FILE Save scan report to FILE\n");
|
mprintf(LOGG_INFO, " --log=FILE -l FILE Save scan report to FILE.\n");
|
||||||
mprintf(LOGG_INFO, " --recursive[=yes/no(*)] -r Scan subdirectories recursively\n");
|
mprintf(LOGG_INFO, " --recursive[=yes/no(*)] -r Scan subdirectories recursively.\n");
|
||||||
mprintf(LOGG_INFO, " --allmatch[=yes/no(*)] -z Continue scanning within file after finding a match\n");
|
mprintf(LOGG_INFO, " --allmatch[=yes/no(*)] -z Continue scanning within file after finding a match.\n");
|
||||||
mprintf(LOGG_INFO, " --cross-fs[=yes(*)/no] Scan files and directories on other filesystems\n");
|
mprintf(LOGG_INFO, " --cross-fs[=yes(*)/no] Scan files and directories on other filesystems.\n");
|
||||||
mprintf(LOGG_INFO, " --follow-dir-symlinks[=0/1(*)/2] Follow directory symlinks (0 = never, 1 = direct, 2 = always)\n");
|
mprintf(LOGG_INFO, " --follow-dir-symlinks[=0/1(*)/2] Follow directory symlinks (0 = never, 1 = direct, 2 = always).\n");
|
||||||
mprintf(LOGG_INFO, " --follow-file-symlinks[=0/1(*)/2] Follow file symlinks (0 = never, 1 = direct, 2 = always)\n");
|
mprintf(LOGG_INFO, " --follow-file-symlinks[=0/1(*)/2] Follow file symlinks (0 = never, 1 = direct, 2 = always).\n");
|
||||||
mprintf(LOGG_INFO, " --file-list=FILE -f FILE Scan files from FILE\n");
|
mprintf(LOGG_INFO, " --file-list=FILE -f FILE Scan files from FILE.\n");
|
||||||
mprintf(LOGG_INFO, " --remove[=yes/no(*)] Remove infected files. Be careful!\n");
|
mprintf(LOGG_INFO, " --remove[=yes/no(*)] Remove infected files. Be careful!\n");
|
||||||
mprintf(LOGG_INFO, " --move=DIRECTORY Move infected files into DIRECTORY\n");
|
mprintf(LOGG_INFO, " --move=DIRECTORY Move infected files into DIRECTORY.\n");
|
||||||
mprintf(LOGG_INFO, " --copy=DIRECTORY Copy infected files into DIRECTORY\n");
|
mprintf(LOGG_INFO, " --copy=DIRECTORY Copy infected files into DIRECTORY.\n");
|
||||||
mprintf(LOGG_INFO, " --exclude=REGEX Don't scan file names matching REGEX\n");
|
mprintf(LOGG_INFO, " --exclude=REGEX Don't scan file names matching REGEX.\n");
|
||||||
mprintf(LOGG_INFO, " --exclude-dir=REGEX Don't scan directories matching REGEX\n");
|
mprintf(LOGG_INFO, " --exclude-dir=REGEX Don't scan directories matching REGEX.\n");
|
||||||
mprintf(LOGG_INFO, " --include=REGEX Only scan file names matching REGEX\n");
|
mprintf(LOGG_INFO, " --include=REGEX Only scan file names matching REGEX.\n");
|
||||||
mprintf(LOGG_INFO, " --include-dir=REGEX Only scan directories matching REGEX\n");
|
mprintf(LOGG_INFO, " --include-dir=REGEX Only scan directories matching REGEX.\n");
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
mprintf(LOGG_INFO, " --memory Scan loaded executable modules\n");
|
mprintf(LOGG_INFO, " --memory Scan loaded executable modules.\n");
|
||||||
mprintf(LOGG_INFO, " --kill Kill/Unload infected loaded modules\n");
|
mprintf(LOGG_INFO, " --kill Kill/Unload infected loaded modules.\n");
|
||||||
mprintf(LOGG_INFO, " --unload Unload infected modules from processes\n");
|
mprintf(LOGG_INFO, " --unload Unload infected modules from processes.\n");
|
||||||
#endif
|
#endif
|
||||||
mprintf(LOGG_INFO, "\n");
|
mprintf(LOGG_INFO, "\n");
|
||||||
mprintf(LOGG_INFO, " --bytecode[=yes(*)/no] Load bytecode from the database\n");
|
mprintf(LOGG_INFO, " --bytecode[=yes(*)/no] Load bytecode from the database.\n");
|
||||||
mprintf(LOGG_INFO, " --bytecode-unsigned[=yes/no(*)] Load unsigned bytecode\n");
|
mprintf(LOGG_INFO, " --bytecode-unsigned[=yes/no(*)] Load unsigned bytecode.\n");
|
||||||
mprintf(LOGG_INFO, " **Caution**: You should NEVER run bytecode signatures from untrusted sources.\n");
|
mprintf(LOGG_INFO, " **Caution**: You should NEVER run bytecode signatures from untrusted sources.\n");
|
||||||
mprintf(LOGG_INFO, " Doing so may result in arbitrary code execution.\n");
|
mprintf(LOGG_INFO, " Doing so may result in arbitrary code execution.\n");
|
||||||
mprintf(LOGG_INFO, " --bytecode-timeout=N Set bytecode timeout (in milliseconds)\n");
|
mprintf(LOGG_INFO, " --bytecode-timeout=N Set bytecode timeout (in milliseconds).\n");
|
||||||
mprintf(LOGG_INFO, " --statistics[=none(*)/bytecode/pcre] Collect and print execution statistics\n");
|
mprintf(LOGG_INFO, " --statistics[=none(*)/bytecode/pcre] Collect and print execution statistics.\n");
|
||||||
mprintf(LOGG_INFO, " --detect-pua[=yes/no(*)] Detect Possibly Unwanted Applications\n");
|
mprintf(LOGG_INFO, " --detect-pua[=yes/no(*)] Detect Possibly Unwanted Applications.\n");
|
||||||
mprintf(LOGG_INFO, " --exclude-pua=CAT Skip PUA sigs of category CAT\n");
|
mprintf(LOGG_INFO, " --exclude-pua=CAT Skip PUA sigs of category CAT.\n");
|
||||||
mprintf(LOGG_INFO, " --include-pua=CAT Load PUA sigs of category CAT\n");
|
mprintf(LOGG_INFO, " --include-pua=CAT Load PUA sigs of category CAT.\n");
|
||||||
mprintf(LOGG_INFO, " --detect-structured[=yes/no(*)] Detect structured data (SSN, Credit Card)\n");
|
mprintf(LOGG_INFO, " --detect-structured[=yes/no(*)] Detect structured data (SSN, Credit Card).\n");
|
||||||
mprintf(LOGG_INFO, " --structured-ssn-format=X SSN format (0=normal,1=stripped,2=both)\n");
|
mprintf(LOGG_INFO, " --structured-ssn-format=X SSN format (0=normal,1=stripped,2=both).\n");
|
||||||
mprintf(LOGG_INFO, " --structured-ssn-count=N Min SSN count to generate a detect\n");
|
mprintf(LOGG_INFO, " --structured-ssn-count=N Min SSN count to generate a detect.\n");
|
||||||
mprintf(LOGG_INFO, " --structured-cc-count=N Min CC count to generate a detect\n");
|
mprintf(LOGG_INFO, " --structured-cc-count=N Min CC count to generate a detect.\n");
|
||||||
mprintf(LOGG_INFO, " --structured-cc-mode=X CC mode (0=credit debit and private label, 1=credit cards only\n");
|
mprintf(LOGG_INFO, " --structured-cc-mode=X CC mode (0=credit debit and private label, 1=credit cards only.\n");
|
||||||
mprintf(LOGG_INFO, " --scan-mail[=yes(*)/no] Scan mail files\n");
|
mprintf(LOGG_INFO, " --scan-mail[=yes(*)/no] Scan mail files.\n");
|
||||||
mprintf(LOGG_INFO, " --phishing-sigs[=yes(*)/no] Enable email signature-based phishing detection\n");
|
mprintf(LOGG_INFO, " --phishing-sigs[=yes(*)/no] Enable email signature-based phishing detection.\n");
|
||||||
mprintf(LOGG_INFO, " --phishing-scan-urls[=yes(*)/no] Enable URL signature-based phishing detection\n");
|
mprintf(LOGG_INFO, " --phishing-scan-urls[=yes(*)/no] Enable URL signature-based phishing detection.\n");
|
||||||
mprintf(LOGG_INFO, " --heuristic-alerts[=yes(*)/no] Heuristic alerts\n");
|
mprintf(LOGG_INFO, " --heuristic-alerts[=yes(*)/no] Heuristic alerts.\n");
|
||||||
mprintf(LOGG_INFO, " --heuristic-scan-precedence[=yes/no(*)] Stop scanning as soon as a heuristic match is found\n");
|
mprintf(LOGG_INFO, " --heuristic-scan-precedence[=yes/no(*)] Stop scanning as soon as a heuristic match is found.\n");
|
||||||
mprintf(LOGG_INFO, " --normalize[=yes(*)/no] Normalize html, script, and text files. Use normalize=no for yara compatibility\n");
|
mprintf(LOGG_INFO, " --normalize[=yes(*)/no] Normalize html, script, and text files. Use normalize=no for yara compatibility.\n");
|
||||||
mprintf(LOGG_INFO, " --scan-pe[=yes(*)/no] Scan PE files\n");
|
mprintf(LOGG_INFO, " --scan-pe[=yes(*)/no] Scan PE files.\n");
|
||||||
mprintf(LOGG_INFO, " --scan-elf[=yes(*)/no] Scan ELF files\n");
|
mprintf(LOGG_INFO, " --scan-elf[=yes(*)/no] Scan ELF files.\n");
|
||||||
mprintf(LOGG_INFO, " --scan-ole2[=yes(*)/no] Scan OLE2 containers\n");
|
mprintf(LOGG_INFO, " --scan-ole2[=yes(*)/no] Scan OLE2 containers.\n");
|
||||||
mprintf(LOGG_INFO, " --scan-pdf[=yes(*)/no] Scan PDF files\n");
|
mprintf(LOGG_INFO, " --scan-pdf[=yes(*)/no] Scan PDF files.\n");
|
||||||
mprintf(LOGG_INFO, " --scan-swf[=yes(*)/no] Scan SWF files\n");
|
mprintf(LOGG_INFO, " --scan-swf[=yes(*)/no] Scan SWF files.\n");
|
||||||
mprintf(LOGG_INFO, " --scan-html[=yes(*)/no] Scan HTML files\n");
|
mprintf(LOGG_INFO, " --scan-html[=yes(*)/no] Scan HTML files.\n");
|
||||||
mprintf(LOGG_INFO, " --scan-xmldocs[=yes(*)/no] Scan xml-based document files\n");
|
mprintf(LOGG_INFO, " --scan-xmldocs[=yes(*)/no] Scan xml-based document files.\n");
|
||||||
mprintf(LOGG_INFO, " --scan-hwp3[=yes(*)/no] Scan HWP3 files\n");
|
mprintf(LOGG_INFO, " --scan-hwp3[=yes(*)/no] Scan HWP3 files.\n");
|
||||||
mprintf(LOGG_INFO, " --scan-onenote[=yes(*)/no] Scan OneNote files\n");
|
mprintf(LOGG_INFO, " --scan-onenote[=yes(*)/no] Scan OneNote files.\n");
|
||||||
mprintf(LOGG_INFO, " --scan-archive[=yes(*)/no] Scan archive files (supported by libclamav)\n");
|
mprintf(LOGG_INFO, " --scan-archive[=yes(*)/no] Scan archive files (supported by libclamav).\n");
|
||||||
mprintf(LOGG_INFO, " --scan-image[=yes(*)/no] Scan image (graphics) files\n");
|
mprintf(LOGG_INFO, " --scan-image[=yes(*)/no] Scan image (graphics) files.\n");
|
||||||
mprintf(LOGG_INFO, " --scan-image-fuzzy-hash[=yes(*)/no] Detect files by calculating image (graphics) fuzzy hashes\n");
|
mprintf(LOGG_INFO, " --scan-image-fuzzy-hash[=yes(*)/no] Detect files by calculating image (graphics) fuzzy hashes.\n");
|
||||||
mprintf(LOGG_INFO, " --alert-broken[=yes/no(*)] Alert on broken executable files (PE & ELF)\n");
|
mprintf(LOGG_INFO, " --alert-broken[=yes/no(*)] Alert on broken executable files (PE & ELF).\n");
|
||||||
mprintf(LOGG_INFO, " --alert-broken-media[=yes/no(*)] Alert on broken graphics files (JPEG, TIFF, PNG, GIF)\n");
|
mprintf(LOGG_INFO, " --alert-broken-media[=yes/no(*)] Alert on broken graphics files (JPEG, TIFF, PNG, GIF).\n");
|
||||||
mprintf(LOGG_INFO, " --alert-encrypted[=yes/no(*)] Alert on encrypted archives and documents\n");
|
mprintf(LOGG_INFO, " --alert-encrypted[=yes/no(*)] Alert on encrypted archives and documents.\n");
|
||||||
mprintf(LOGG_INFO, " --alert-encrypted-archive[=yes/no(*)] Alert on encrypted archives\n");
|
mprintf(LOGG_INFO, " --alert-encrypted-archive[=yes/no(*)] Alert on encrypted archives.\n");
|
||||||
mprintf(LOGG_INFO, " --alert-encrypted-doc[=yes/no(*)] Alert on encrypted documents\n");
|
mprintf(LOGG_INFO, " --alert-encrypted-doc[=yes/no(*)] Alert on encrypted documents.\n");
|
||||||
mprintf(LOGG_INFO, " --alert-macros[=yes/no(*)] Alert on OLE2 files containing VBA macros\n");
|
mprintf(LOGG_INFO, " --alert-macros[=yes/no(*)] Alert on OLE2 files containing VBA macros.\n");
|
||||||
mprintf(LOGG_INFO, " --alert-exceeds-max[=yes/no(*)] Alert on files that exceed max file size, max scan size, or max recursion limit\n");
|
mprintf(LOGG_INFO, " --alert-exceeds-max[=yes/no(*)] Alert on files that exceed max file size, max scan size, or max recursion limit.\n");
|
||||||
mprintf(LOGG_INFO, " --alert-phishing-ssl[=yes/no(*)] Alert on emails containing SSL mismatches in URLs\n");
|
mprintf(LOGG_INFO, " --alert-phishing-ssl[=yes/no(*)] Alert on emails containing SSL mismatches in URLs.\n");
|
||||||
mprintf(LOGG_INFO, " --alert-phishing-cloak[=yes/no(*)] Alert on emails containing cloaked URLs\n");
|
mprintf(LOGG_INFO, " --alert-phishing-cloak[=yes/no(*)] Alert on emails containing cloaked URLs.\n");
|
||||||
mprintf(LOGG_INFO, " --alert-partition-intersection[=yes/no(*)] Alert on raw DMG image files containing partition intersections\n");
|
mprintf(LOGG_INFO, " --alert-partition-intersection[=yes/no(*)] Alert on raw DMG image files containing partition intersections.\n");
|
||||||
mprintf(LOGG_INFO, " --nocerts Disable authenticode certificate chain verification in PE files\n");
|
mprintf(LOGG_INFO, " --nocerts Disable authenticode certificate chain verification in PE files.\n");
|
||||||
mprintf(LOGG_INFO, " --dumpcerts Dump authenticode certificate chain in PE files\n");
|
mprintf(LOGG_INFO, " --dumpcerts Dump authenticode certificate chain in PE files.\n");
|
||||||
mprintf(LOGG_INFO, "\n");
|
mprintf(LOGG_INFO, "\n");
|
||||||
mprintf(LOGG_INFO, " --max-scantime=#n Scan time longer than this will be skipped and assumed clean (milliseconds)\n");
|
mprintf(LOGG_INFO, " --max-scantime=#n Scan time longer than this will be skipped and assumed clean (milliseconds).\n");
|
||||||
mprintf(LOGG_INFO, " --max-filesize=#n Files larger than this will be skipped and assumed clean\n");
|
mprintf(LOGG_INFO, " --max-filesize=#n Files larger than this will be skipped and assumed clean.\n");
|
||||||
mprintf(LOGG_INFO, " --max-scansize=#n The maximum amount of data to scan for each container file (**)\n");
|
mprintf(LOGG_INFO, " --max-scansize=#n The maximum amount of data to scan for each container file (**).\n");
|
||||||
mprintf(LOGG_INFO, " --max-files=#n The maximum number of files to scan for each container file (**)\n");
|
mprintf(LOGG_INFO, " --max-files=#n The maximum number of files to scan for each container file (**).\n");
|
||||||
mprintf(LOGG_INFO, " --max-recursion=#n Maximum archive recursion level for container file (**)\n");
|
mprintf(LOGG_INFO, " --max-recursion=#n Maximum archive recursion level for container file (**).\n");
|
||||||
mprintf(LOGG_INFO, " --max-dir-recursion=#n Maximum directory recursion level\n");
|
mprintf(LOGG_INFO, " --max-dir-recursion=#n Maximum directory recursion level.\n");
|
||||||
mprintf(LOGG_INFO, " --max-embeddedpe=#n Maximum size file to check for embedded PE\n");
|
mprintf(LOGG_INFO, " --max-embeddedpe=#n Maximum size file to check for embedded PE.\n");
|
||||||
mprintf(LOGG_INFO, " --max-htmlnormalize=#n Maximum size of HTML file to normalize\n");
|
mprintf(LOGG_INFO, " --max-htmlnormalize=#n Maximum size of HTML file to normalize.\n");
|
||||||
mprintf(LOGG_INFO, " --max-htmlnotags=#n Maximum size of normalized HTML file to scan\n");
|
mprintf(LOGG_INFO, " --max-htmlnotags=#n Maximum size of normalized HTML file to scan.\n");
|
||||||
mprintf(LOGG_INFO, " --max-scriptnormalize=#n Maximum size of script file to normalize\n");
|
mprintf(LOGG_INFO, " --max-scriptnormalize=#n Maximum size of script file to normalize.\n");
|
||||||
mprintf(LOGG_INFO, " --max-ziptypercg=#n Maximum size zip to type reanalyze\n");
|
mprintf(LOGG_INFO, " --max-ziptypercg=#n Maximum size zip to type reanalyze.\n");
|
||||||
mprintf(LOGG_INFO, " --max-partitions=#n Maximum number of partitions in disk image to be scanned\n");
|
mprintf(LOGG_INFO, " --max-partitions=#n Maximum number of partitions in disk image to be scanned.\n");
|
||||||
mprintf(LOGG_INFO, " --max-iconspe=#n Maximum number of icons in PE file to be scanned\n");
|
mprintf(LOGG_INFO, " --max-iconspe=#n Maximum number of icons in PE file to be scanned.\n");
|
||||||
mprintf(LOGG_INFO, " --max-rechwp3=#n Maximum recursive calls to HWP3 parsing function\n");
|
mprintf(LOGG_INFO, " --max-rechwp3=#n Maximum recursive calls to HWP3 parsing function.\n");
|
||||||
mprintf(LOGG_INFO, " --pcre-match-limit=#n Maximum calls to the PCRE match function.\n");
|
mprintf(LOGG_INFO, " --pcre-match-limit=#n Maximum calls to the PCRE match function.\n");
|
||||||
mprintf(LOGG_INFO, " --pcre-recmatch-limit=#n Maximum recursive calls to the PCRE match function.\n");
|
mprintf(LOGG_INFO, " --pcre-recmatch-limit=#n Maximum recursive calls to the PCRE match function.\n");
|
||||||
mprintf(LOGG_INFO, " --pcre-max-filesize=#n Maximum size file to perform PCRE subsig matching.\n");
|
mprintf(LOGG_INFO, " --pcre-max-filesize=#n Maximum size file to perform PCRE subsig matching.\n");
|
||||||
mprintf(LOGG_INFO, " --disable-cache Disable caching and cache checks for hash sums of scanned files.\n");
|
mprintf(LOGG_INFO, " --disable-cache Disable caching and cache checks for hash sums of scanned files.\n");
|
||||||
|
mprintf(LOGG_INFO, " --hash-hint The file hash so that libclamav does not need to calculate it.\n");
|
||||||
|
mprintf(LOGG_INFO, " The type of hash must match the '--hash-alg'.\n");
|
||||||
|
mprintf(LOGG_INFO, " --log-hash Print the file hash after each file scanned.\n");
|
||||||
|
mprintf(LOGG_INFO, " The type of hash printed will match the '--hash-alg'.\n");
|
||||||
|
mprintf(LOGG_INFO, " --hash-alg The hashing algorithm used for either '--hash-hint' or '--log-hash'.\n");
|
||||||
|
mprintf(LOGG_INFO, " Supported algorithms are 'md5', 'sha1', 'sha2-256'.\n");
|
||||||
|
mprintf(LOGG_INFO, " If not specified, the default is 'sha2-256'.\n");
|
||||||
|
mprintf(LOGG_INFO, " --file-type-hint The file type hint so that libclamav can optimize scanning.\n");
|
||||||
|
mprintf(LOGG_INFO, " E.g. 'pe', 'elf', 'zip', etc.\n");
|
||||||
|
mprintf(LOGG_INFO, " You may also use ClamAV type names such as 'CL_TYPE_PE'.\n");
|
||||||
|
mprintf(LOGG_INFO, " ClamAV will ignore the hint if it is not familiar with the specified type.\n");
|
||||||
|
mprintf(LOGG_INFO, " See also: https://docs.clamav.net/appendix/FileTypes.html#file-types\n");
|
||||||
|
mprintf(LOGG_INFO, " --log-file-type Print the file type after each file scanned.\n");
|
||||||
mprintf(LOGG_INFO, " --cvdcertsdir=DIRECTORY Specify a directory containing the root\n");
|
mprintf(LOGG_INFO, " --cvdcertsdir=DIRECTORY Specify a directory containing the root\n");
|
||||||
mprintf(LOGG_INFO, " CA cert needed to verify detached CVD digital signatures.\n");
|
mprintf(LOGG_INFO, " CA cert needed to verify detached CVD digital signatures.\n");
|
||||||
mprintf(LOGG_INFO, " If not provided, then clamscan will look in the default directory.\n");
|
mprintf(LOGG_INFO, " If not provided, then clamscan will look in the default directory.\n");
|
||||||
|
mprintf(LOGG_INFO, " --fips-limits Enforce FIPS-like limits on using hash algorithms for\n");
|
||||||
|
mprintf(LOGG_INFO, " cryptographic purposes. Will disable MD5 & SHA1.\n");
|
||||||
|
mprintf(LOGG_INFO, " FP sigs and will require '.sign' files to verify CVD\n");
|
||||||
|
mprintf(LOGG_INFO, " authenticity.\n");
|
||||||
mprintf(LOGG_INFO, "\n");
|
mprintf(LOGG_INFO, "\n");
|
||||||
mprintf(LOGG_INFO, "Environment Variables:\n");
|
mprintf(LOGG_INFO, "Environment Variables:\n");
|
||||||
mprintf(LOGG_INFO, "\n");
|
mprintf(LOGG_INFO, "\n");
|
||||||
|
|
|
@ -23,13 +23,13 @@
|
||||||
#define __GLOBAL_H
|
#define __GLOBAL_H
|
||||||
|
|
||||||
struct s_info {
|
struct s_info {
|
||||||
unsigned int sigs; /* number of signatures */
|
unsigned int sigs; /* number of signatures */
|
||||||
unsigned int dirs; /* number of scanned directories */
|
unsigned int dirs; /* number of scanned directories */
|
||||||
unsigned int files; /* number of scanned files */
|
unsigned int files; /* number of scanned files */
|
||||||
unsigned int ifiles; /* number of infected files */
|
unsigned int ifiles; /* number of infected files */
|
||||||
unsigned int errors; /* number of errors */
|
unsigned int errors; /* number of errors */
|
||||||
unsigned long int blocks; /* number of *scanned* 16kb blocks */
|
uint64_t bytes_scanned; /* number of *scanned* bytes */
|
||||||
unsigned long int rblocks; /* number of *read* 16kb blocks */
|
uint64_t bytes_read; /* number of *read* bytes */
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct s_info info;
|
extern struct s_info info;
|
||||||
|
|
|
@ -181,7 +181,7 @@ static int print_chain(struct metachain *c, char *str, size_t len)
|
||||||
return i == c->nchains - 1 ? 0 : 1;
|
return i == c->nchains - 1 ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static cl_error_t post(int fd, int result, const char *virname, void *context)
|
static cl_error_t post(int fd, int result, const char *alert_name, void *context)
|
||||||
{
|
{
|
||||||
struct clamscan_cb_data *d = context;
|
struct clamscan_cb_data *d = context;
|
||||||
struct metachain *c = NULL;
|
struct metachain *c = NULL;
|
||||||
|
@ -196,10 +196,10 @@ static cl_error_t post(int fd, int result, const char *virname, void *context)
|
||||||
if (c && c->nchains) {
|
if (c && c->nchains) {
|
||||||
print_chain(c, str, sizeof(str));
|
print_chain(c, str, sizeof(str));
|
||||||
|
|
||||||
if (c->level == c->lastadd && !virname)
|
if (c->level == c->lastadd && !alert_name)
|
||||||
free(c->chains[--c->nchains]);
|
free(c->chains[--c->nchains]);
|
||||||
|
|
||||||
if (virname && !c->lastvir)
|
if (alert_name && !c->lastvir)
|
||||||
c->lastvir = c->level;
|
c->lastvir = c->level;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -275,7 +275,7 @@ static cl_error_t meta(const char *container_type, unsigned long fsize_container
|
||||||
return CL_CLEAN;
|
return CL_CLEAN;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void clamscan_virus_found_cb(int fd, const char *virname, void *context)
|
static void clamscan_virus_found_cb(int fd, const char *alert_name, void *context)
|
||||||
{
|
{
|
||||||
struct clamscan_cb_data *data = (struct clamscan_cb_data *)context;
|
struct clamscan_cb_data *data = (struct clamscan_cb_data *)context;
|
||||||
const char *filename;
|
const char *filename;
|
||||||
|
@ -288,20 +288,29 @@ static void clamscan_virus_found_cb(int fd, const char *virname, void *context)
|
||||||
filename = data->filename;
|
filename = data->filename;
|
||||||
else
|
else
|
||||||
filename = "(filename not set)";
|
filename = "(filename not set)";
|
||||||
logg(LOGG_INFO, "%s: %s FOUND\n", filename, virname);
|
logg(LOGG_INFO, "%s: %s FOUND\n", filename, alert_name);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void scanfile(const char *filename, struct cl_engine *engine, const struct optstruct *opts, struct cl_scan_options *options)
|
static void scanfile(const char *filename, struct cl_engine *engine, const struct optstruct *opts, struct cl_scan_options *options)
|
||||||
{
|
{
|
||||||
cl_error_t ret = CL_SUCCESS;
|
cl_error_t ret = CL_SUCCESS;
|
||||||
int fd, included;
|
int fd = -1;
|
||||||
|
int included = 0;
|
||||||
unsigned i;
|
unsigned i;
|
||||||
const struct optstruct *opt;
|
const struct optstruct *opt;
|
||||||
const char *virname = NULL;
|
cl_verdict_t verdict = CL_VERDICT_NOTHING_FOUND;
|
||||||
|
const char *alert_name = NULL;
|
||||||
STATBUF sb;
|
STATBUF sb;
|
||||||
struct metachain chain;
|
struct metachain chain = {0};
|
||||||
struct clamscan_cb_data data;
|
struct clamscan_cb_data data = {0};
|
||||||
|
const char *hash_hint = NULL;
|
||||||
|
char **hash_out = NULL;
|
||||||
|
char *hash = NULL;
|
||||||
|
const char *hash_alg = NULL;
|
||||||
|
const char *file_type_hint = NULL;
|
||||||
|
char **file_type_out = NULL;
|
||||||
|
char *file_type = NULL;
|
||||||
|
|
||||||
char *real_filename = NULL;
|
char *real_filename = NULL;
|
||||||
|
|
||||||
|
@ -369,7 +378,7 @@ static void scanfile(const char *filename, struct cl_engine *engine, const struc
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
info.rblocks += sb.st_size / CL_COUNT_PRECISION;
|
info.bytes_read += sb.st_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
|
@ -399,6 +408,22 @@ static void scanfile(const char *filename, struct cl_engine *engine, const struc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((opt = optget(opts, "hash-alg"))->enabled) {
|
||||||
|
hash_alg = opt->strarg;
|
||||||
|
}
|
||||||
|
if ((opt = optget(opts, "hash-hint"))->enabled) {
|
||||||
|
hash_hint = opt->strarg;
|
||||||
|
}
|
||||||
|
if ((opt = optget(opts, "log-hash"))->enabled) {
|
||||||
|
hash_out = &hash;
|
||||||
|
}
|
||||||
|
if ((opt = optget(opts, "file-type-hint"))->enabled) {
|
||||||
|
file_type_hint = opt->strarg;
|
||||||
|
}
|
||||||
|
if ((opt = optget(opts, "log-file-type"))->enabled) {
|
||||||
|
file_type_out = &file_type;
|
||||||
|
}
|
||||||
|
|
||||||
logg(LOGG_DEBUG, "Scanning %s\n", filename);
|
logg(LOGG_DEBUG, "Scanning %s\n", filename);
|
||||||
|
|
||||||
if ((fd = safe_open(filename, O_RDONLY | O_BINARY)) == -1) {
|
if ((fd = safe_open(filename, O_RDONLY | O_BINARY)) == -1) {
|
||||||
|
@ -409,47 +434,104 @@ static void scanfile(const char *filename, struct cl_engine *engine, const struc
|
||||||
|
|
||||||
data.chain = &chain;
|
data.chain = &chain;
|
||||||
data.filename = filename;
|
data.filename = filename;
|
||||||
if ((ret = cl_scandesc_callback(fd, filename, &virname, &info.blocks, engine, options, &data)) == CL_VIRUS) {
|
|
||||||
if (optget(opts, "archive-verbose")->enabled) {
|
|
||||||
if (chain.nchains > 1) {
|
|
||||||
char str[128];
|
|
||||||
int toolong = print_chain(&chain, str, sizeof(str));
|
|
||||||
|
|
||||||
logg(LOGG_INFO, "%s%s!(%llu)%s: %s FOUND\n", str, toolong ? "..." : "", (long long unsigned)(chain.lastvir - 1), chain.chains[chain.nchains - 1], virname);
|
ret = cl_scandesc_ex(
|
||||||
} else if (chain.lastvir) {
|
fd,
|
||||||
logg(LOGG_INFO, "%s!(%llu): %s FOUND\n", filename, (long long unsigned)(chain.lastvir - 1), virname);
|
filename,
|
||||||
|
&verdict,
|
||||||
|
&alert_name,
|
||||||
|
&info.bytes_scanned,
|
||||||
|
engine, options,
|
||||||
|
&data,
|
||||||
|
hash_hint,
|
||||||
|
hash_out,
|
||||||
|
hash_alg,
|
||||||
|
file_type_hint,
|
||||||
|
file_type_out);
|
||||||
|
|
||||||
|
switch (verdict) {
|
||||||
|
case CL_VERDICT_NOTHING_FOUND: {
|
||||||
|
if (CL_SUCCESS == ret) {
|
||||||
|
if (!printinfected && printclean) {
|
||||||
|
mprintf(LOGG_INFO, "%s: OK\n", filename);
|
||||||
|
}
|
||||||
|
info.files++;
|
||||||
|
} else {
|
||||||
|
if (!printinfected)
|
||||||
|
logg(LOGG_INFO, "%s: %s ERROR\n", filename, cl_strerror(ret));
|
||||||
|
|
||||||
|
info.errors++;
|
||||||
}
|
}
|
||||||
}
|
} break;
|
||||||
info.files++;
|
|
||||||
info.ifiles++;
|
|
||||||
|
|
||||||
if (bell)
|
case CL_VERDICT_TRUSTED: {
|
||||||
fprintf(stderr, "\007");
|
// TODO: Option to print "TRUSTED" verdict instead of "OK"?
|
||||||
} else if (ret == CL_CLEAN) {
|
if (!printinfected && printclean) {
|
||||||
if (!printinfected && printclean)
|
mprintf(LOGG_INFO, "%s: OK\n", filename);
|
||||||
mprintf(LOGG_INFO, "%s: OK\n", filename);
|
}
|
||||||
|
info.files++;
|
||||||
|
} break;
|
||||||
|
|
||||||
info.files++;
|
case CL_VERDICT_STRONG_INDICATOR:
|
||||||
} else {
|
case CL_VERDICT_POTENTIALLY_UNWANTED: {
|
||||||
if (!printinfected)
|
if (optget(opts, "archive-verbose")->enabled) {
|
||||||
logg(LOGG_INFO, "%s: %s ERROR\n", filename, cl_strerror(ret));
|
if (chain.nchains > 1) {
|
||||||
|
char str[128];
|
||||||
|
int toolong = print_chain(&chain, str, sizeof(str));
|
||||||
|
|
||||||
info.errors++;
|
logg(LOGG_INFO, "%s%s!(%llu)%s: %s FOUND\n", str, toolong ? "..." : "", (long long unsigned)(chain.lastvir - 1), chain.chains[chain.nchains - 1], alert_name);
|
||||||
|
} else if (chain.lastvir) {
|
||||||
|
logg(LOGG_INFO, "%s!(%llu): %s FOUND\n", filename, (long long unsigned)(chain.lastvir - 1), alert_name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
info.files++;
|
||||||
|
info.ifiles++;
|
||||||
|
|
||||||
|
if (bell) {
|
||||||
|
fprintf(stderr, "\007");
|
||||||
|
}
|
||||||
|
} break;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < chain.nchains; i++)
|
if (NULL != hash) {
|
||||||
free(chain.chains[i]);
|
if (hash_alg == NULL) {
|
||||||
|
// libclamav defaults to sha2-256
|
||||||
|
hash_alg = "sha2-256";
|
||||||
|
}
|
||||||
|
logg(LOGG_INFO, "%s FileHash: %s (%s)\n", filename, hash, hash_alg);
|
||||||
|
}
|
||||||
|
|
||||||
free(chain.chains);
|
if (NULL != file_type) {
|
||||||
close(fd);
|
logg(LOGG_INFO, "%s FileType: %s\n", filename, file_type);
|
||||||
|
}
|
||||||
if (ret == CL_VIRUS && action)
|
|
||||||
action(filename);
|
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
/*
|
||||||
|
* Run the action callback if the file was infected.
|
||||||
|
*/
|
||||||
|
if (((verdict == CL_VERDICT_STRONG_INDICATOR) || (verdict == CL_VERDICT_POTENTIALLY_UNWANTED)) && action) {
|
||||||
|
action(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NULL != hash) {
|
||||||
|
free(hash);
|
||||||
|
}
|
||||||
|
if (NULL != file_type) {
|
||||||
|
free(file_type);
|
||||||
|
}
|
||||||
|
if (NULL != chain.chains) {
|
||||||
|
for (i = 0; i < chain.nchains; i++) {
|
||||||
|
free(chain.chains[i]);
|
||||||
|
}
|
||||||
|
free(chain.chains);
|
||||||
|
}
|
||||||
|
if (fd != -1) {
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
if (NULL != real_filename) {
|
if (NULL != real_filename) {
|
||||||
free(real_filename);
|
free(real_filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -565,16 +647,26 @@ static void scandirs(const char *dirname, struct cl_engine *engine, const struct
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int scanstdin(const struct cl_engine *engine, struct cl_scan_options *options)
|
static int scanstdin(const struct cl_engine *engine, const struct optstruct *opts, struct cl_scan_options *options)
|
||||||
{
|
{
|
||||||
int ret;
|
cl_error_t ret;
|
||||||
unsigned int fsize = 0;
|
|
||||||
const char *virname = NULL;
|
size_t fsize = 0;
|
||||||
const char *tmpdir = NULL;
|
cl_verdict_t verdict = CL_VERDICT_NOTHING_FOUND;
|
||||||
char *file, buff[FILEBUFF];
|
const char *alert_name = NULL;
|
||||||
|
const char *tmpdir = NULL;
|
||||||
|
char *filename, buff[FILEBUFF];
|
||||||
size_t bread;
|
size_t bread;
|
||||||
FILE *fs;
|
FILE *fs;
|
||||||
struct clamscan_cb_data data;
|
struct clamscan_cb_data data;
|
||||||
|
const struct optstruct *opt;
|
||||||
|
const char *hash_hint = NULL;
|
||||||
|
char **hash_out = NULL;
|
||||||
|
char *hash = NULL;
|
||||||
|
const char *hash_alg = NULL;
|
||||||
|
const char *file_type_hint = NULL;
|
||||||
|
char **file_type_out = NULL;
|
||||||
|
char *file_type = NULL;
|
||||||
|
|
||||||
tmpdir = cl_engine_get_str(engine, CL_ENGINE_TMPDIR, NULL);
|
tmpdir = cl_engine_get_str(engine, CL_ENGINE_TMPDIR, NULL);
|
||||||
if (NULL == tmpdir) {
|
if (NULL == tmpdir) {
|
||||||
|
@ -586,22 +678,22 @@ static int scanstdin(const struct cl_engine *engine, struct cl_scan_options *opt
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(file = cli_gentemp(tmpdir))) {
|
if (!(filename = cli_gentemp(tmpdir))) {
|
||||||
logg(LOGG_ERROR, "Can't generate tempfile name\n");
|
logg(LOGG_ERROR, "Can't generate tempfile name\n");
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(fs = fopen(file, "wb"))) {
|
if (!(fs = fopen(filename, "wb"))) {
|
||||||
logg(LOGG_ERROR, "Can't open %s for writing\n", file);
|
logg(LOGG_ERROR, "Can't open %s for writing\n", filename);
|
||||||
free(file);
|
free(filename);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
while ((bread = fread(buff, 1, FILEBUFF, stdin))) {
|
while ((bread = fread(buff, 1, FILEBUFF, stdin))) {
|
||||||
fsize += bread;
|
fsize += bread;
|
||||||
if (fwrite(buff, 1, bread, fs) < bread) {
|
if (fwrite(buff, 1, bread, fs) < bread) {
|
||||||
logg(LOGG_ERROR, "Can't write to %s\n", file);
|
logg(LOGG_ERROR, "Can't write to %s\n", filename);
|
||||||
free(file);
|
free(filename);
|
||||||
fclose(fs);
|
fclose(fs);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
@ -609,30 +701,98 @@ static int scanstdin(const struct cl_engine *engine, struct cl_scan_options *opt
|
||||||
|
|
||||||
fclose(fs);
|
fclose(fs);
|
||||||
|
|
||||||
logg(LOGG_DEBUG, "Checking %s\n", file);
|
if ((opt = optget(opts, "hash-alg"))->enabled) {
|
||||||
|
hash_alg = opt->strarg;
|
||||||
|
}
|
||||||
|
if ((opt = optget(opts, "hash-hint"))->enabled) {
|
||||||
|
hash_hint = opt->strarg;
|
||||||
|
}
|
||||||
|
if ((opt = optget(opts, "log-hash"))->enabled) {
|
||||||
|
hash_out = &hash;
|
||||||
|
}
|
||||||
|
if ((opt = optget(opts, "file-type-hint"))->enabled) {
|
||||||
|
file_type_hint = opt->strarg;
|
||||||
|
}
|
||||||
|
if ((opt = optget(opts, "log-file-type"))->enabled) {
|
||||||
|
file_type_out = &file_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
logg(LOGG_DEBUG, "Scanning %s\n", filename);
|
||||||
|
|
||||||
info.files++;
|
info.files++;
|
||||||
info.rblocks += fsize / CL_COUNT_PRECISION;
|
info.bytes_read += fsize;
|
||||||
|
|
||||||
data.filename = "stdin";
|
data.filename = "stdin";
|
||||||
data.chain = NULL;
|
data.chain = NULL;
|
||||||
if ((ret = cl_scanfile_callback(file, &virname, &info.blocks, engine, options, &data)) == CL_VIRUS) {
|
|
||||||
info.ifiles++;
|
|
||||||
|
|
||||||
if (bell)
|
ret = cl_scanfile_ex(
|
||||||
fprintf(stderr, "\007");
|
filename,
|
||||||
} else if (ret == CL_CLEAN) {
|
&verdict,
|
||||||
if (!printinfected)
|
&alert_name,
|
||||||
mprintf(LOGG_INFO, "stdin: OK\n");
|
&info.bytes_scanned,
|
||||||
} else {
|
engine,
|
||||||
if (!printinfected)
|
options,
|
||||||
logg(LOGG_INFO, "stdin: %s ERROR\n", cl_strerror(ret));
|
&data,
|
||||||
|
hash_hint,
|
||||||
|
hash_out,
|
||||||
|
hash_alg,
|
||||||
|
file_type_hint,
|
||||||
|
file_type_out);
|
||||||
|
|
||||||
info.errors++;
|
switch (verdict) {
|
||||||
|
case CL_VERDICT_NOTHING_FOUND: {
|
||||||
|
if (CL_SUCCESS == ret) {
|
||||||
|
if (!printinfected) {
|
||||||
|
mprintf(LOGG_INFO, "stdin: OK\n");
|
||||||
|
}
|
||||||
|
info.files++;
|
||||||
|
} else {
|
||||||
|
if (!printinfected) {
|
||||||
|
logg(LOGG_INFO, "stdin: %s ERROR\n", cl_strerror(ret));
|
||||||
|
}
|
||||||
|
info.errors++;
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case CL_VERDICT_TRUSTED: {
|
||||||
|
// TODO: Option to print "TRUSTED" verdict instead of "OK"?
|
||||||
|
if (!printinfected) {
|
||||||
|
mprintf(LOGG_INFO, "stdin: OK\n");
|
||||||
|
}
|
||||||
|
} break;
|
||||||
|
|
||||||
|
case CL_VERDICT_STRONG_INDICATOR:
|
||||||
|
case CL_VERDICT_POTENTIALLY_UNWANTED: {
|
||||||
|
info.ifiles++;
|
||||||
|
|
||||||
|
if (bell) {
|
||||||
|
fprintf(stderr, "\007");
|
||||||
|
}
|
||||||
|
} break;
|
||||||
}
|
}
|
||||||
|
|
||||||
unlink(file);
|
if (NULL != hash) {
|
||||||
free(file);
|
if (hash_alg == NULL) {
|
||||||
|
// libclamav defaults to sha2-256
|
||||||
|
hash_alg = "sha2-256";
|
||||||
|
}
|
||||||
|
logg(LOGG_INFO, "%s FileHash: %s (%s)\n", filename, hash, hash_alg);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NULL != file_type) {
|
||||||
|
logg(LOGG_INFO, "%s FileType: %s\n", filename, file_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NULL != hash) {
|
||||||
|
free(hash);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NULL != file_type) {
|
||||||
|
free(file_type);
|
||||||
|
}
|
||||||
|
|
||||||
|
unlink(filename);
|
||||||
|
free(filename);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -927,18 +1087,18 @@ static int scan_memory(struct cl_engine *engine, const struct optstruct *opts, s
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
struct mem_info minfo;
|
struct mem_info minfo;
|
||||||
|
|
||||||
minfo.d = 0;
|
minfo.d = 0;
|
||||||
minfo.files = info.files;
|
minfo.files = info.files;
|
||||||
minfo.ifiles = info.ifiles;
|
minfo.ifiles = info.ifiles;
|
||||||
minfo.blocks = info.blocks;
|
minfo.bytes_scanned = info.bytes_scanned;
|
||||||
minfo.engine = engine;
|
minfo.engine = engine;
|
||||||
minfo.opts = opts;
|
minfo.opts = opts;
|
||||||
minfo.options = options;
|
minfo.options = options;
|
||||||
ret = scanmem(&minfo);
|
ret = scanmem(&minfo);
|
||||||
|
|
||||||
info.files = minfo.files;
|
info.files = minfo.files;
|
||||||
info.ifiles = minfo.ifiles;
|
info.ifiles = minfo.ifiles;
|
||||||
info.blocks = minfo.blocks;
|
info.bytes_scanned = minfo.bytes_scanned;
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -976,7 +1136,7 @@ static int scan_files(struct cl_engine *engine, const struct optstruct *opts, st
|
||||||
while ((filename = filelist(opts, &ret)) && (file = strdup(filename))) {
|
while ((filename = filelist(opts, &ret)) && (file = strdup(filename))) {
|
||||||
if (!strcmp(file, "-")) {
|
if (!strcmp(file, "-")) {
|
||||||
/* scan data from stdin */
|
/* scan data from stdin */
|
||||||
ret = scanstdin(engine, options);
|
ret = scanstdin(engine, opts, options);
|
||||||
} else if (LSTAT(file, &sb) == -1) {
|
} else if (LSTAT(file, &sb) == -1) {
|
||||||
/* Can't access the file */
|
/* Can't access the file */
|
||||||
perror(file);
|
perror(file);
|
||||||
|
@ -1196,8 +1356,12 @@ int scanmanager(const struct optstruct *opts)
|
||||||
if (optget(opts, "dev-ac-depth")->enabled)
|
if (optget(opts, "dev-ac-depth")->enabled)
|
||||||
cl_engine_set_num(engine, CL_ENGINE_AC_MAXDEPTH, optget(opts, "dev-ac-depth")->numarg);
|
cl_engine_set_num(engine, CL_ENGINE_AC_MAXDEPTH, optget(opts, "dev-ac-depth")->numarg);
|
||||||
|
|
||||||
if (optget(opts, "leave-temps")->enabled)
|
if (optget(opts, "leave-temps")->enabled) {
|
||||||
|
/* Set the engine to keep temporary files */
|
||||||
cl_engine_set_num(engine, CL_ENGINE_KEEPTMP, 1);
|
cl_engine_set_num(engine, CL_ENGINE_KEEPTMP, 1);
|
||||||
|
/* Also set the engine to create temporary directory structure */
|
||||||
|
cl_engine_set_num(engine, CL_ENGINE_TMPDIR_RECURSION, 1);
|
||||||
|
}
|
||||||
|
|
||||||
if (optget(opts, "force-to-disk")->enabled)
|
if (optget(opts, "force-to-disk")->enabled)
|
||||||
cl_engine_set_num(engine, CL_ENGINE_FORCETODISK, 1);
|
cl_engine_set_num(engine, CL_ENGINE_FORCETODISK, 1);
|
||||||
|
@ -1240,6 +1404,11 @@ int scanmanager(const struct optstruct *opts)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (optget(opts, "fips-limits")->enabled) {
|
||||||
|
dboptions |= CL_DB_FIPS_LIMITS;
|
||||||
|
cl_engine_set_num(engine, CL_ENGINE_FIPS_LIMITS, 1);
|
||||||
|
}
|
||||||
|
|
||||||
if (optget(opts, "gen-json")->enabled) {
|
if (optget(opts, "gen-json")->enabled) {
|
||||||
options.general |= CL_SCAN_GENERAL_COLLECT_METADATA;
|
options.general |= CL_SCAN_GENERAL_COLLECT_METADATA;
|
||||||
}
|
}
|
||||||
|
@ -1252,6 +1421,10 @@ int scanmanager(const struct optstruct *opts)
|
||||||
options.general |= CL_SCAN_GENERAL_STORE_PDF_URIS;
|
options.general |= CL_SCAN_GENERAL_STORE_PDF_URIS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (optget(opts, "json-store-extra-hashes")->enabled) {
|
||||||
|
options.general |= CL_SCAN_GENERAL_STORE_EXTRA_HASHES;
|
||||||
|
}
|
||||||
|
|
||||||
if ((opt = optget(opts, "tempdir"))->enabled) {
|
if ((opt = optget(opts, "tempdir"))->enabled) {
|
||||||
if ((ret = cl_engine_set_str(engine, CL_ENGINE_TMPDIR, opt->strarg))) {
|
if ((ret = cl_engine_set_str(engine, CL_ENGINE_TMPDIR, opt->strarg))) {
|
||||||
logg(LOGG_ERROR, "cli_engine_set_str(CL_ENGINE_TMPDIR) failed: %s\n", cl_strerror(ret));
|
logg(LOGG_ERROR, "cli_engine_set_str(CL_ENGINE_TMPDIR) failed: %s\n", cl_strerror(ret));
|
||||||
|
@ -1612,11 +1785,6 @@ int scanmanager(const struct optstruct *opts)
|
||||||
options.heuristic |= CL_SCAN_HEURISTIC_EXCEEDS_MAX;
|
options.heuristic |= CL_SCAN_HEURISTIC_EXCEEDS_MAX;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE__INTERNAL__SHA_COLLECT
|
|
||||||
if (optget(opts, "dev-collect-hashes")->enabled)
|
|
||||||
options.dev |= CL_SCAN_DEV_COLLECT_SHA;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (optget(opts, "dev-performance")->enabled)
|
if (optget(opts, "dev-performance")->enabled)
|
||||||
options.dev |= CL_SCAN_DEV_COLLECT_PERFORMANCE_INFO;
|
options.dev |= CL_SCAN_DEV_COLLECT_PERFORMANCE_INFO;
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,7 @@ Imported Targets
|
||||||
This module provides the following imported targets, if found:
|
This module provides the following imported targets, if found:
|
||||||
|
|
||||||
``Curses::curses``
|
``Curses::curses``
|
||||||
The CURSES library
|
The CURSES library and possibly TINFO library
|
||||||
|
|
||||||
Result Variables
|
Result Variables
|
||||||
^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^
|
||||||
|
@ -34,20 +34,26 @@ Cache Variables
|
||||||
|
|
||||||
The following cache variables may also be set:
|
The following cache variables may also be set:
|
||||||
|
|
||||||
``CURSES_INCLUDE_DIR``
|
``NCURSES_INCLUDE_DIR``
|
||||||
The directory containing ``foo.h``.
|
The directory containing ``ncurses.h``.
|
||||||
|
``PDCURSES_INCLUDE_DIR``
|
||||||
|
The directory containing ``curses.h``.
|
||||||
``CURSES_LIBRARY``
|
``CURSES_LIBRARY``
|
||||||
The path to the CURSES library.
|
The path to the CURSES library.
|
||||||
|
``TINFO_LIBRARY``
|
||||||
|
The path to the TINFO library.
|
||||||
|
|
||||||
#]=======================================================================]
|
#]=======================================================================]
|
||||||
|
|
||||||
find_package(PkgConfig QUIET)
|
if(NOT NCURSES_INCLUDE_DIR)
|
||||||
# First try for NCurses
|
find_package(PkgConfig QUIET)
|
||||||
pkg_search_module (PC_NCurses QUIET ncurses ncursesw)
|
# First try for NCurses
|
||||||
|
pkg_search_module (PC_NCurses QUIET ncurses ncursesw)
|
||||||
|
endif()
|
||||||
|
|
||||||
find_path(NCURSES_INCLUDE_DIR
|
find_path(NCURSES_INCLUDE_DIR
|
||||||
NAMES ncurses.h
|
NAMES ncurses.h
|
||||||
PATHS ${PC_NCurses_INCLUDE_DIRS} ${CURSES_INCLUDE_DIR}
|
PATHS ${PC_NCurses_INCLUDE_DIRS} ${CURSES_INCLUDE_DIR}
|
||||||
)
|
)
|
||||||
|
|
||||||
string(FIND ${NCURSES_INCLUDE_DIR} "-NOTFOUND" NCURSES_NOT_FOUND)
|
string(FIND ${NCURSES_INCLUDE_DIR} "-NOTFOUND" NCURSES_NOT_FOUND)
|
||||||
|
@ -69,82 +75,99 @@ if(NCURSES_NOT_FOUND EQUAL -1)
|
||||||
|
|
||||||
include(FindPackageHandleStandardArgs)
|
include(FindPackageHandleStandardArgs)
|
||||||
find_package_handle_standard_args(CURSES
|
find_package_handle_standard_args(CURSES
|
||||||
FOUND_VAR CURSES_FOUND
|
FOUND_VAR CURSES_FOUND
|
||||||
REQUIRED_VARS
|
REQUIRED_VARS
|
||||||
CURSES_LIBRARY
|
CURSES_LIBRARY
|
||||||
NCURSES_INCLUDE_DIR
|
NCURSES_INCLUDE_DIR
|
||||||
VERSION_VAR CURSES_VERSION
|
VERSION_VAR CURSES_VERSION
|
||||||
|
)
|
||||||
|
|
||||||
|
include(FindPackageHandleStandardArgs)
|
||||||
|
find_package_handle_standard_args(TINFO
|
||||||
|
FOUND_VAR TINFO_FOUND
|
||||||
|
REQUIRED_VARS
|
||||||
|
TINFO_LIBRARY
|
||||||
|
NCURSES_INCLUDE_DIR
|
||||||
|
VERSION_VAR CURSES_VERSION
|
||||||
|
NAME_MISMATCHED
|
||||||
)
|
)
|
||||||
|
|
||||||
set(HAVE_LIBNCURSES 1)
|
set(HAVE_LIBNCURSES 1)
|
||||||
set(CURSES_INCLUDE "<ncurses.h>")
|
set(CURSES_INCLUDE "<ncurses.h>")
|
||||||
|
|
||||||
set(CURSES_LIBRARIES ${CURSES_LIBRARY})
|
if(NOT TINFO_FOUND)
|
||||||
|
set(CURSES_LIBRARIES "${CURSES_LIBRARY}")
|
||||||
|
else()
|
||||||
|
set(CURSES_LIBRARIES "${CURSES_LIBRARY};${TINFO_LIBRARY}")
|
||||||
|
endif()
|
||||||
|
|
||||||
set(CURSES_INCLUDE_DIRS ${NCURSES_INCLUDE_DIR})
|
set(CURSES_INCLUDE_DIRS ${NCURSES_INCLUDE_DIR})
|
||||||
set(CURSES_DEFINITIONS ${PC_NCurses_CFLAGS_OTHER})
|
set(CURSES_DEFINITIONS ${PC_NCurses_CFLAGS_OTHER})
|
||||||
|
|
||||||
if (NOT TARGET Curses::curses)
|
if (NOT TARGET Curses::curses)
|
||||||
add_library(Curses::curses INTERFACE IMPORTED)
|
add_library(Curses::curses INTERFACE IMPORTED)
|
||||||
set_target_properties(Curses::curses PROPERTIES
|
set_target_properties(Curses::curses PROPERTIES
|
||||||
INTERFACE_COMPILE_OPTIONS "${PC_NCurses_CFLAGS_OTHER}"
|
INTERFACE_COMPILE_OPTIONS "${PC_NCurses_CFLAGS_OTHER}"
|
||||||
INTERFACE_INCLUDE_DIRECTORIES "${CURSES_INCLUDE_DIRS}"
|
INTERFACE_INCLUDE_DIRECTORIES "${CURSES_INCLUDE_DIRS}"
|
||||||
INTERFACE_LINK_LIBRARIES "${CURSES_LIBRARY}"
|
INTERFACE_LINK_LIBRARIES "${CURSES_LIBRARIES}"
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
else()
|
else()
|
||||||
# Try for PDCurses
|
# Try for PDCurses
|
||||||
pkg_check_modules(PC_PDCurses QUIET curses)
|
pkg_check_modules(PC_PDCurses QUIET curses)
|
||||||
|
|
||||||
find_path(PDCURSES_INCLUDE_DIR
|
find_path(PDCURSES_INCLUDE_DIR
|
||||||
NAMES curses.h
|
NAMES curses.h
|
||||||
PATHS ${PC_PDCurses_INCLUDE_DIRS} ${CURSES_INCLUDE_DIR}
|
PATHS ${PC_PDCurses_INCLUDE_DIRS} ${CURSES_INCLUDE_DIR}
|
||||||
)
|
)
|
||||||
|
|
||||||
string(FIND ${PDCURSES_INCLUDE_DIR} "-NOTFOUND" PDCURSES_NOT_FOUND)
|
string(FIND ${PDCURSES_INCLUDE_DIR} "-NOTFOUND" PDCURSES_NOT_FOUND)
|
||||||
if(PDCURSES_NOT_FOUND EQUAL -1)
|
if(PDCURSES_NOT_FOUND EQUAL -1)
|
||||||
#
|
#
|
||||||
# pdcurses WAS found!
|
# pdcurses WAS found!
|
||||||
#
|
#
|
||||||
set(HAVE_LIBPDCURSES 1)
|
set(HAVE_LIBPDCURSES 1)
|
||||||
set(CURSES_INCLUDE "<curses.h>")
|
set(CURSES_INCLUDE "<curses.h>")
|
||||||
|
|
||||||
find_library(CURSES_LIBRARY
|
find_library(CURSES_LIBRARY
|
||||||
NAMES curses pdcurses
|
NAMES curses pdcurses
|
||||||
PATHS ${PC_PDCurses_LIBRARY_DIRS}
|
PATHS ${PC_PDCurses_LIBRARY_DIRS}
|
||||||
)
|
|
||||||
|
|
||||||
set(CURSES_VERSION ${PC_PDCurses_VERSION})
|
|
||||||
|
|
||||||
include(FindPackageHandleStandardArgs)
|
|
||||||
find_package_handle_standard_args(CURSES
|
|
||||||
FOUND_VAR CURSES_FOUND
|
|
||||||
REQUIRED_VARS
|
|
||||||
CURSES_LIBRARY
|
|
||||||
PDCURSES_INCLUDE_DIR
|
|
||||||
VERSION_VAR CURSES_VERSION
|
|
||||||
)
|
|
||||||
|
|
||||||
set(HAVE_LIBPDCURSES 1)
|
|
||||||
set(CURSES_INCLUDE "<curses.h>")
|
|
||||||
|
|
||||||
set(CURSES_LIBRARIES ${CURSES_LIBRARY})
|
|
||||||
set(CURSES_INCLUDE_DIRS ${PDCURSES_INCLUDE_DIR})
|
|
||||||
set(CURSES_DEFINITIONS ${PC_PDCurses_CFLAGS_OTHER})
|
|
||||||
|
|
||||||
if (NOT TARGET Curses::curses)
|
|
||||||
add_library(Curses::curses UNKNOWN IMPORTED)
|
|
||||||
set_target_properties(Curses::curses PROPERTIES
|
|
||||||
INTERFACE_COMPILE_OPTIONS "${PC_PDCurses_CFLAGS_OTHER}"
|
|
||||||
INTERFACE_INCLUDE_DIRECTORIES "${CURSES_INCLUDE_DIRS}"
|
|
||||||
IMPORTED_LOCATION "${CURSES_LIBRARY}"
|
|
||||||
)
|
)
|
||||||
endif()
|
|
||||||
else()
|
set(CURSES_VERSION ${PC_PDCurses_VERSION})
|
||||||
message(FATAL_ERROR "Unable to find ncurses or pdcurses")
|
|
||||||
endif()
|
include(FindPackageHandleStandardArgs)
|
||||||
|
find_package_handle_standard_args(CURSES
|
||||||
|
FOUND_VAR CURSES_FOUND
|
||||||
|
REQUIRED_VARS
|
||||||
|
CURSES_LIBRARY
|
||||||
|
PDCURSES_INCLUDE_DIR
|
||||||
|
VERSION_VAR CURSES_VERSION
|
||||||
|
)
|
||||||
|
|
||||||
|
set(HAVE_LIBPDCURSES 1)
|
||||||
|
set(CURSES_INCLUDE "<curses.h>")
|
||||||
|
|
||||||
|
set(CURSES_LIBRARIES ${CURSES_LIBRARY})
|
||||||
|
set(CURSES_INCLUDE_DIRS ${PDCURSES_INCLUDE_DIR})
|
||||||
|
set(CURSES_DEFINITIONS ${PC_PDCurses_CFLAGS_OTHER})
|
||||||
|
|
||||||
|
if (NOT TARGET Curses::curses)
|
||||||
|
add_library(Curses::curses UNKNOWN IMPORTED)
|
||||||
|
set_target_properties(Curses::curses PROPERTIES
|
||||||
|
INTERFACE_COMPILE_OPTIONS "${PC_PDCurses_CFLAGS_OTHER}"
|
||||||
|
INTERFACE_INCLUDE_DIRECTORIES "${CURSES_INCLUDE_DIRS}"
|
||||||
|
IMPORTED_LOCATION "${CURSES_LIBRARIES}"
|
||||||
|
)
|
||||||
|
endif()
|
||||||
|
else()
|
||||||
|
message(FATAL_ERROR "Unable to find ncurses or pdcurses")
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
mark_as_advanced(
|
mark_as_advanced(
|
||||||
CURSES_INCLUDE_DIR
|
NCURSES_INCLUDE_DIR
|
||||||
CURSES_LIBRARY
|
PDCURSES_INCLUDE_DIR
|
||||||
|
CURSES_LIBRARY
|
||||||
|
TINFO_LIBRARY
|
||||||
)
|
)
|
||||||
|
|
|
@ -452,7 +452,7 @@ static int traverse_rename(const char *source, const char *destination)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef _WIN32
|
#ifndef _WIN32
|
||||||
ret = cli_basename(source, strlen(source), &source_basename);
|
ret = cli_basename(source, strlen(source), &source_basename, false /* posix_support_backslash_pathsep */);
|
||||||
if (CL_SUCCESS != ret) {
|
if (CL_SUCCESS != ret) {
|
||||||
logg(LOGG_INFO, "traverse_rename: Failed to get basename of source path:%s\n\tError: %d\n", source, (int)ret);
|
logg(LOGG_INFO, "traverse_rename: Failed to get basename of source path:%s\n\tError: %d\n", source, (int)ret);
|
||||||
goto done;
|
goto done;
|
||||||
|
@ -564,7 +564,7 @@ static int traverse_unlink(const char *target)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = cli_basename(target, strlen(target), &target_basename);
|
ret = cli_basename(target, strlen(target), &target_basename, false /* posix_support_backslash_pathsep */);
|
||||||
if (CL_SUCCESS != ret) {
|
if (CL_SUCCESS != ret) {
|
||||||
logg(LOGG_INFO, "traverse_unlink: Failed to get basename of target path: %s\n\tError: %d\n", target, (int)ret);
|
logg(LOGG_INFO, "traverse_unlink: Failed to get basename of target path: %s\n\tError: %d\n", target, (int)ret);
|
||||||
goto done;
|
goto done;
|
||||||
|
|
|
@ -60,7 +60,7 @@
|
||||||
#define CLAMKEY "Software\\ClamAV"
|
#define CLAMKEY "Software\\ClamAV"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define MAXCMDOPTS 150
|
#define MAXCMDOPTS 200
|
||||||
#define MAX_OPTION_LINE_LENGTH 1024
|
#define MAX_OPTION_LINE_LENGTH 1024
|
||||||
|
|
||||||
#define MATCH_NUMBER "^[0-9]+((( +)?#(.*))?)$"
|
#define MATCH_NUMBER "^[0-9]+((( +)?#(.*))?)$"
|
||||||
|
@ -161,10 +161,15 @@ const struct clam_option __clam_options[] = {
|
||||||
{NULL, "include", 0, CLOPT_TYPE_STRING, NULL, -1, NULL, FLAG_MULTIPLE, OPT_CLAMSCAN, "", ""},
|
{NULL, "include", 0, CLOPT_TYPE_STRING, NULL, -1, NULL, FLAG_MULTIPLE, OPT_CLAMSCAN, "", ""},
|
||||||
{NULL, "include-dir", 0, CLOPT_TYPE_STRING, NULL, -1, NULL, FLAG_MULTIPLE, OPT_CLAMSCAN, "", ""},
|
{NULL, "include-dir", 0, CLOPT_TYPE_STRING, NULL, -1, NULL, FLAG_MULTIPLE, OPT_CLAMSCAN, "", ""},
|
||||||
{NULL, "structured-ssn-format", 0, CLOPT_TYPE_NUMBER, MATCH_NUMBER, 0, NULL, 0, OPT_CLAMSCAN, "", ""},
|
{NULL, "structured-ssn-format", 0, CLOPT_TYPE_NUMBER, MATCH_NUMBER, 0, NULL, 0, OPT_CLAMSCAN, "", ""},
|
||||||
|
{NULL, "hash-hint", 0, CLOPT_TYPE_STRING, NULL, -1, NULL, 0, OPT_CLAMSCAN, "", ""},
|
||||||
|
{NULL, "hash-alg", 0, CLOPT_TYPE_STRING, NULL, -1, NULL, 0, OPT_CLAMSCAN, "", ""},
|
||||||
|
{NULL, "file-type-hint", 0, CLOPT_TYPE_STRING, NULL, -1, NULL, 0, OPT_CLAMSCAN, "", ""},
|
||||||
|
{NULL, "log-hash", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMSCAN, "", ""},
|
||||||
|
{NULL, "log-file-type", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMSCAN, "", ""},
|
||||||
{NULL, "hex-dump", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_SIGTOOL, "", ""},
|
{NULL, "hex-dump", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_SIGTOOL, "", ""},
|
||||||
{NULL, "md5", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_SIGTOOL, "", ""},
|
{NULL, "md5", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_SIGTOOL, "", ""},
|
||||||
{NULL, "sha1", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_SIGTOOL, "", ""},
|
{NULL, "sha1", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_SIGTOOL, "", ""},
|
||||||
{NULL, "sha256", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_SIGTOOL, "", ""},
|
{NULL, "sha2-256", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_SIGTOOL, "", ""},
|
||||||
{NULL, "mdb", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_SIGTOOL, "", ""},
|
{NULL, "mdb", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_SIGTOOL, "", ""},
|
||||||
{NULL, "imp", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_SIGTOOL, "", ""},
|
{NULL, "imp", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_SIGTOOL, "", ""},
|
||||||
{NULL, "fuzzy-img", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_SIGTOOL, "", ""},
|
{NULL, "fuzzy-img", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_SIGTOOL, "", ""},
|
||||||
|
@ -252,6 +257,7 @@ const struct clam_option __clam_options[] = {
|
||||||
{NULL, "tar", 0, CLOPT_TYPE_STRING, NULL, -1, "foo", 0, OPT_CLAMSCAN | OPT_DEPRECATED, "", ""},
|
{NULL, "tar", 0, CLOPT_TYPE_STRING, NULL, -1, "foo", 0, OPT_CLAMSCAN | OPT_DEPRECATED, "", ""},
|
||||||
{NULL, "tgz", 0, CLOPT_TYPE_STRING, NULL, -1, "foo", 0, OPT_CLAMSCAN | OPT_DEPRECATED, "", ""},
|
{NULL, "tgz", 0, CLOPT_TYPE_STRING, NULL, -1, "foo", 0, OPT_CLAMSCAN | OPT_DEPRECATED, "", ""},
|
||||||
{NULL, "deb", 0, CLOPT_TYPE_STRING, NULL, -1, "foo", 0, OPT_CLAMSCAN | OPT_DEPRECATED, "", ""},
|
{NULL, "deb", 0, CLOPT_TYPE_STRING, NULL, -1, "foo", 0, OPT_CLAMSCAN | OPT_DEPRECATED, "", ""},
|
||||||
|
{NULL, "sha256", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_SIGTOOL, "", ""}, // OPT_DEPRECATED not used so that it will still function for now.
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
{NULL, "memory", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMSCAN | OPT_CLAMDSCAN, "", ""},
|
{NULL, "memory", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMSCAN | OPT_CLAMDSCAN, "", ""},
|
||||||
|
@ -381,8 +387,12 @@ const struct clam_option __clam_options[] = {
|
||||||
|
|
||||||
{"JsonStorePDFURIs", "json-store-pdf-uris", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 1, NULL, 0, OPT_CLAMD | OPT_CLAMSCAN, "When GenerateMetadataJson enabled: store uris found in pdf /URI tags.", "yes"},
|
{"JsonStorePDFURIs", "json-store-pdf-uris", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 1, NULL, 0, OPT_CLAMD | OPT_CLAMSCAN, "When GenerateMetadataJson enabled: store uris found in pdf /URI tags.", "yes"},
|
||||||
|
|
||||||
|
{"JsonStoreExtraHashes", "json-store-extra-hashes", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMD | OPT_CLAMSCAN, "When GenerateMetadataJson enabled: calculate and store each type of supported file hash.", "yes"},
|
||||||
|
|
||||||
{"User", NULL, 0, CLOPT_TYPE_STRING, NULL, -1, NULL, 0, OPT_CLAMD | OPT_MILTER, "Run the daemon as a specified user (the process must be started by root).", "clamav"},
|
{"User", NULL, 0, CLOPT_TYPE_STRING, NULL, -1, NULL, 0, OPT_CLAMD | OPT_MILTER, "Run the daemon as a specified user (the process must be started by root).", "clamav"},
|
||||||
|
|
||||||
|
{"FIPSCryptoHashLimits", "fips-limits", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_FRESHCLAM | OPT_CLAMSCAN | OPT_CLAMD | OPT_SIGTOOL | OPT_CLAMONACC, "Apply FIPS-like limitations on which hash algorithms may be used for cryptographic purposes. This essentially disables the legacy CVD digital signature verfication method, and also disables support for MD5 and SHA1 false positive signatures ('.fp' and '.sfp' signatures using MD5 or SHA1).", "yes"},
|
||||||
|
|
||||||
/* Scan options */
|
/* Scan options */
|
||||||
{"Bytecode", "bytecode", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 1, NULL, 0, OPT_CLAMD | OPT_CLAMSCAN, "With this option enabled ClamAV will load bytecode from the database. It is highly recommended you keep this option on, otherwise you'll miss detections for many new viruses.", "yes"},
|
{"Bytecode", "bytecode", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, 1, NULL, 0, OPT_CLAMD | OPT_CLAMSCAN, "With this option enabled ClamAV will load bytecode from the database. It is highly recommended you keep this option on, otherwise you'll miss detections for many new viruses.", "yes"},
|
||||||
|
|
||||||
|
@ -546,9 +556,6 @@ const struct clam_option __clam_options[] = {
|
||||||
|
|
||||||
{"DevACDepth", "dev-ac-depth", 0, CLOPT_TYPE_NUMBER, MATCH_NUMBER, -1, NULL, FLAG_HIDDEN, OPT_CLAMD | OPT_CLAMSCAN, "", ""},
|
{"DevACDepth", "dev-ac-depth", 0, CLOPT_TYPE_NUMBER, MATCH_NUMBER, -1, NULL, FLAG_HIDDEN, OPT_CLAMD | OPT_CLAMSCAN, "", ""},
|
||||||
|
|
||||||
#ifdef HAVE__INTERNAL__SHA_COLLECT
|
|
||||||
{"DevCollectHashes", "dev-collect-hashes", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, -1, NULL, FLAG_HIDDEN, OPT_CLAMD | OPT_CLAMSCAN, "", ""},
|
|
||||||
#endif
|
|
||||||
{"DevPerformance", "dev-performance", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, -1, NULL, FLAG_HIDDEN, OPT_CLAMD | OPT_CLAMSCAN, "", ""},
|
{"DevPerformance", "dev-performance", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, -1, NULL, FLAG_HIDDEN, OPT_CLAMD | OPT_CLAMSCAN, "", ""},
|
||||||
{"DevLiblog", "dev-liblog", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, -1, NULL, FLAG_HIDDEN, OPT_CLAMD, "", ""},
|
{"DevLiblog", "dev-liblog", 0, CLOPT_TYPE_BOOL, MATCH_BOOL, -1, NULL, FLAG_HIDDEN, OPT_CLAMD, "", ""},
|
||||||
|
|
||||||
|
@ -1248,15 +1255,17 @@ struct optstruct *optparse(const char *cfgfile, int argc, char **argv, int verbo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Find and remove inline comments. */
|
if (NULL != arg) {
|
||||||
numarg = -1;
|
/* Find and remove inline comments. */
|
||||||
inlinecomment = strchr(arg, '#');
|
numarg = -1;
|
||||||
if (inlinecomment != NULL) {
|
inlinecomment = strchr(arg, '#');
|
||||||
/* Found a '#', indicating an inline comment. Strip it off along with any leading spaces or tabs. */
|
if (inlinecomment != NULL) {
|
||||||
arg = strtok(arg, "#");
|
/* Found a '#', indicating an inline comment. Strip it off along with any leading spaces or tabs. */
|
||||||
trim_comment = arg + strlen(arg) - 1;
|
arg = strtok(arg, "#");
|
||||||
while (trim_comment >= arg && (*trim_comment == ' ' || *trim_comment == '\t')) {
|
trim_comment = arg + strlen(arg) - 1;
|
||||||
*(trim_comment--) = '\0';
|
while (trim_comment >= arg && (*trim_comment == ' ' || *trim_comment == '\t')) {
|
||||||
|
*(trim_comment--) = '\0';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -533,8 +533,10 @@ int scanfile(const char *filename, scanmem_data *scan_data, struct mem_info *inf
|
||||||
{
|
{
|
||||||
int fd;
|
int fd;
|
||||||
int scantype;
|
int scantype;
|
||||||
int ret = CL_CLEAN;
|
int ret = CL_CLEAN;
|
||||||
const char *virname = NULL;
|
|
||||||
|
cl_verdict_t verdict = CL_VERDICT_NOTHING_FOUND;
|
||||||
|
const char *alert_name = NULL;
|
||||||
|
|
||||||
logg(LOGG_DEBUG, "Scanning %s\n", filename);
|
logg(LOGG_DEBUG, "Scanning %s\n", filename);
|
||||||
|
|
||||||
|
@ -562,12 +564,38 @@ int scanfile(const char *filename, scanmem_data *scan_data, struct mem_info *inf
|
||||||
ret = CL_VIRUS;
|
ret = CL_VIRUS;
|
||||||
}
|
}
|
||||||
} else { // clamscan
|
} else { // clamscan
|
||||||
ret = cl_scandesc(fd, filename, &virname, &info->blocks, info->engine, info->options);
|
ret = cl_scandesc_ex(
|
||||||
if (ret == CL_VIRUS) {
|
fd,
|
||||||
logg(LOGG_INFO, "%s: %s FOUND\n", filename, virname);
|
filename,
|
||||||
info->ifiles++;
|
&verdict,
|
||||||
} else if (scan_data->printclean) {
|
&alert_name,
|
||||||
logg(LOGG_INFO, "%s: OK \n", filename);
|
&info->bytes_scanned,
|
||||||
|
info->engine,
|
||||||
|
info->options,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
NULL);
|
||||||
|
|
||||||
|
switch (verdict) {
|
||||||
|
case CL_VERDICT_NOTHING_FOUND: {
|
||||||
|
logg(LOGG_INFO, "%s: OK \n", filename);
|
||||||
|
ret = CL_CLEAN;
|
||||||
|
} break;
|
||||||
|
case CL_VERDICT_TRUSTED: {
|
||||||
|
// TODO: Option to print "TRUSTED" verdict instead of "OK"?
|
||||||
|
logg(LOGG_INFO, "%s: OK \n", filename);
|
||||||
|
ret = CL_CLEAN;
|
||||||
|
} break;
|
||||||
|
case CL_VERDICT_STRONG_INDICATOR:
|
||||||
|
case CL_VERDICT_POTENTIALLY_UNWANTED: {
|
||||||
|
logg(LOGG_INFO, "%s: %s FOUND\n", filename, alert_name);
|
||||||
|
info->ifiles++;
|
||||||
|
ret = CL_VIRUS;
|
||||||
|
} break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,8 @@
|
||||||
#ifndef __SCANMEM_H
|
#ifndef __SCANMEM_H
|
||||||
#define __SCANMEM_H
|
#define __SCANMEM_H
|
||||||
|
|
||||||
|
#include <clamav-types.h>
|
||||||
|
|
||||||
#ifndef TH32CS_SNAPMODULE32
|
#ifndef TH32CS_SNAPMODULE32
|
||||||
#define TH32CS_SNAPMODULE32 0x00000010
|
#define TH32CS_SNAPMODULE32 0x00000010
|
||||||
#endif
|
#endif
|
||||||
|
@ -54,10 +56,10 @@ typedef struct _scanmem_data_t {
|
||||||
} scanmem_data;
|
} scanmem_data;
|
||||||
|
|
||||||
struct mem_info {
|
struct mem_info {
|
||||||
unsigned int d; /*1 = clamdscan, 0 = clamscan */
|
unsigned int d; /*1 = clamdscan, 0 = clamscan */
|
||||||
unsigned int files; /* number of scanned files */
|
unsigned int files; /* number of scanned files */
|
||||||
unsigned int ifiles; /* number of infected files */
|
unsigned int ifiles; /* number of infected files */
|
||||||
unsigned long int blocks; /* number of *scanned* 16kb blocks */
|
uint64_t bytes_scanned; /* number of *scanned* bytes */
|
||||||
unsigned int errors;
|
unsigned int errors;
|
||||||
|
|
||||||
struct cl_engine *engine;
|
struct cl_engine *engine;
|
||||||
|
|
|
@ -102,6 +102,11 @@ Path to a directory containing ClamAV CA certificate files used to verify signed
|
||||||
.br
|
.br
|
||||||
Default: @CERTSDIR@
|
Default: @CERTSDIR@
|
||||||
.TP
|
.TP
|
||||||
|
\fBFIPSCryptoHashLimits BOOL\fR
|
||||||
|
Enforce FIPS\-like limits on using hash algorithms for cryptographic purposes. Will disable MD5 & SHA1 FP sigs and will require '.sign' files to verify CVD authenticity.
|
||||||
|
.br
|
||||||
|
Default: no
|
||||||
|
.TP
|
||||||
\fBOfficialDatabaseOnly BOOL\fR
|
\fBOfficialDatabaseOnly BOOL\fR
|
||||||
Only load the official signatures published by the ClamAV project.
|
Only load the official signatures published by the ClamAV project.
|
||||||
.br
|
.br
|
||||||
|
@ -332,6 +337,26 @@ A metadata.json file will be written to the scan temp directory if LeaveTemporar
|
||||||
.br
|
.br
|
||||||
Default: no
|
Default: no
|
||||||
.TP
|
.TP
|
||||||
|
\fBJsonStoreHTMLURIs BOOL\fR
|
||||||
|
Store URIs found in html files to the json metadata.
|
||||||
|
URIs will be stored in an array with the tag 'URIs'.
|
||||||
|
GenerateMetadataJson is required for this feature.
|
||||||
|
.br
|
||||||
|
Default: yes (if GenerateMetadataJson is used)
|
||||||
|
.TP
|
||||||
|
\fBJsonStorePDFURIs BOOL\fR
|
||||||
|
Store URIs found in pdf files to the json metadata.
|
||||||
|
URIs will be stored in an array with the tag 'URIs'.
|
||||||
|
GenerateMetadataJson is required for this feature.
|
||||||
|
.br
|
||||||
|
Default: yes (if GenerateMetadataJson is used)
|
||||||
|
.TP
|
||||||
|
\fBJsonStoreExtraHashes BOOL\fR
|
||||||
|
Calculate MD5 and SHA1 hashes (in addition to SHA2-256) and store to the json metadata.
|
||||||
|
GenerateMetadataJson is required for this feature.
|
||||||
|
.br
|
||||||
|
Default: no
|
||||||
|
.TP
|
||||||
\fBUser STRING\fR
|
\fBUser STRING\fR
|
||||||
Run the daemon as a specified user (the process must be started by root).
|
Run the daemon as a specified user (the process must be started by root).
|
||||||
.br
|
.br
|
||||||
|
|
|
@ -57,6 +57,15 @@ This option causes memory or nested map scans to dump the content to disk. If yo
|
||||||
\fB\-\-gen\-json\fR
|
\fB\-\-gen\-json\fR
|
||||||
Generate JSON description of scanned file(s). JSON will be printed and also dropped to the temp directory if --leave-temps is enabled.
|
Generate JSON description of scanned file(s). JSON will be printed and also dropped to the temp directory if --leave-temps is enabled.
|
||||||
.TP
|
.TP
|
||||||
|
\fB\-\-json\-store\-html\-uris\fR
|
||||||
|
Store html URIs in metadata. URIs will be written to the metadata.json file in an array called 'URIs'.
|
||||||
|
.TP
|
||||||
|
\fB\-\-json\-store\-pdf\-uris\fR
|
||||||
|
Store pdf URIs in metadata. URIs will be written to the metadata.json file in an array called 'URIs'.
|
||||||
|
.TP
|
||||||
|
\fB\-\-json\-store\-extra\-hashes\fR
|
||||||
|
Store md5 and sha1 in addition to sha2-256 in metadata.
|
||||||
|
.TP
|
||||||
\fB\-d FILE/DIR, \-\-database=FILE/DIR\fR
|
\fB\-d FILE/DIR, \-\-database=FILE/DIR\fR
|
||||||
Load virus database from FILE or load all virus database files from DIR.
|
Load virus database from FILE or load all virus database files from DIR.
|
||||||
.TP
|
.TP
|
||||||
|
@ -274,8 +283,26 @@ Maximum size file to perform PCRE subsig matching (default: 100 MB).
|
||||||
\fB\-\-disable\-cache\fR
|
\fB\-\-disable\-cache\fR
|
||||||
Disable caching and cache checks for hash sums of scanned files.
|
Disable caching and cache checks for hash sums of scanned files.
|
||||||
.TP
|
.TP
|
||||||
|
\fB\-\-hash\-hint\fR
|
||||||
|
The file hash so that libclamav does not need to calculate it. The type of hash must match the '\-\-hash-alg'.
|
||||||
|
.TP
|
||||||
|
\fB\-\-log\-hash\fR
|
||||||
|
Print the file hash after each file scanned. The type of hash printed will match the '\-\-hash-alg'.
|
||||||
|
.TP
|
||||||
|
\fB\-\-hash\-alg\fR
|
||||||
|
The hashing algorithm used for either '\-\-hash\-hint' or '\-\-log\-hash'. Supported algorithms are "md5", "sha1", "sha2\-256". If not specified, the default is "sha2\-256".
|
||||||
|
.TP
|
||||||
|
\fB\-\-file\-type\-hint\fR
|
||||||
|
The file type hint so that libclamav can optimize scanning. E.g. "pe", "elf", "zip", etc. You may also use ClamAV type names such as "CL_TYPE_PE". ClamAV will ignore the hint if it is not familiar with the specified type. See also: https://docs.clamav.net/appendix/FileTypes.html#file-types
|
||||||
|
.TP
|
||||||
|
\fB\-\-log\-file\-type\fR
|
||||||
|
Print the file type after each file scanned.
|
||||||
|
.TP
|
||||||
\fB\-\-cvdcertsdir=DIR\fR
|
\fB\-\-cvdcertsdir=DIR\fR
|
||||||
Specify a directory containing the root CA cert needed to verify detached CVD digital signatures. If not provided, then clamscan will look in the default directory.
|
Specify a directory containing the root CA cert needed to verify detached CVD digital signatures. If not provided, then clamscan will look in the default directory.
|
||||||
|
.TP
|
||||||
|
\fB\-\-fips\-limits\fR
|
||||||
|
Enforce FIPS\-like limits on using hash algorithms for cryptographic purposes. Will disable MD5 & SHA1 FP sigs and will require '.sign' files to verify CVD authenticity.
|
||||||
|
|
||||||
.SH "ENVIRONMENT VARIABLES"
|
.SH "ENVIRONMENT VARIABLES"
|
||||||
.LP
|
.LP
|
||||||
|
|
|
@ -71,6 +71,11 @@ Path to a directory containing ClamAV CA certificate files used to verify signed
|
||||||
.br
|
.br
|
||||||
Default: @CERTSDIR@
|
Default: @CERTSDIR@
|
||||||
.TP
|
.TP
|
||||||
|
\fBFIPSCryptoHashLimits BOOL\fR
|
||||||
|
Enforce FIPS\-like limits on using hash algorithms for cryptographic purposes. Will disable MD5 & SHA1 FP sigs and will require '.sign' files to verify CVD authenticity.
|
||||||
|
.br
|
||||||
|
Default: no
|
||||||
|
.TP
|
||||||
\fBForeground BOOL\fR
|
\fBForeground BOOL\fR
|
||||||
Don't fork into background.
|
Don't fork into background.
|
||||||
.br
|
.br
|
||||||
|
|
|
@ -63,8 +63,9 @@ Generate MD5 checksum from stdin or MD5 sigs for FILES.
|
||||||
\fB\-\-sha1 [FILES]\fR
|
\fB\-\-sha1 [FILES]\fR
|
||||||
Generate SHA1 checksum from stdin or SHA1 sigs for FILES.
|
Generate SHA1 checksum from stdin or SHA1 sigs for FILES.
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-sha256 [FILES]\fR
|
\fB\-\-sha2-256 [FILES]\fR
|
||||||
Generate SHA256 checksum from stdin or SHA256 sigs for FILES.
|
Generate SHA2-256 checksum from stdin or SHA2-256 sigs for FILES.
|
||||||
|
The previous option \-\-sha256 is deprecated and may be removed in a future version.
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-mdb [FILES]\fR
|
\fB\-\-mdb [FILES]\fR
|
||||||
Generate .mdb (PE section hash) signatures for FILES.
|
Generate .mdb (PE section hash) signatures for FILES.
|
||||||
|
@ -144,6 +145,9 @@ Unpack FILE (CVD) to a current directory.
|
||||||
.TP
|
.TP
|
||||||
\fB\-\-unpack\-current\fR
|
\fB\-\-unpack\-current\fR
|
||||||
Unpack a local CVD file (main or daily) to current directory.
|
Unpack a local CVD file (main or daily) to current directory.
|
||||||
|
.TP
|
||||||
|
\fB\-\-fips\-limits\fR
|
||||||
|
Enforce FIPS\-like limits on using hash algorithms for cryptographic purposes. Will disable MD5 & SHA1 FP sigs and will require '.sign' files to verify CVD authenticity.
|
||||||
|
|
||||||
.SH "COMMANDS FOR WORKING WITH CDIFF PATCH FILES"
|
.SH "COMMANDS FOR WORKING WITH CDIFF PATCH FILES"
|
||||||
.LP
|
.LP
|
||||||
|
|
|
@ -89,6 +89,12 @@ Example
|
||||||
# Default: hardcoded (depends on installation options)
|
# Default: hardcoded (depends on installation options)
|
||||||
#CVDCertsDirectory /etc/clamav/certs
|
#CVDCertsDirectory /etc/clamav/certs
|
||||||
|
|
||||||
|
# Enforce FIPS-like limits on using hash algorithms for cryptographic purposes.
|
||||||
|
# Will disable MD5 & SHA1 FP sigs and will require '.sign' files to verify
|
||||||
|
# CVD authenticity.
|
||||||
|
# Default: no
|
||||||
|
#FIPSCryptoHashLimits yes
|
||||||
|
|
||||||
# Only load the official signatures published by the ClamAV project.
|
# Only load the official signatures published by the ClamAV project.
|
||||||
# Default: no
|
# Default: no
|
||||||
#OfficialDatabaseOnly no
|
#OfficialDatabaseOnly no
|
||||||
|
@ -301,6 +307,11 @@ Example
|
||||||
# Default: yes (if GenerateMetadataJson is used)
|
# Default: yes (if GenerateMetadataJson is used)
|
||||||
#JsonStorePDFURIs no
|
#JsonStorePDFURIs no
|
||||||
|
|
||||||
|
# Calculate MD5 and SHA1 hashes (in addition to SHA2-256) and store to the json metadata.
|
||||||
|
# GenerateMetadataJson is required for this feature.
|
||||||
|
# Default: no
|
||||||
|
#JsonStoreExtraHashes yes
|
||||||
|
|
||||||
# Permit use of the ALLMATCHSCAN command. If set to no, clamd will reject
|
# Permit use of the ALLMATCHSCAN command. If set to no, clamd will reject
|
||||||
# any ALLMATCHSCAN command as invalid.
|
# any ALLMATCHSCAN command as invalid.
|
||||||
# Default: yes
|
# Default: yes
|
||||||
|
|
|
@ -22,6 +22,12 @@ Example
|
||||||
# Default: hardcoded (depends on installation options)
|
# Default: hardcoded (depends on installation options)
|
||||||
#CVDCertsDirectory /etc/clamav/certs
|
#CVDCertsDirectory /etc/clamav/certs
|
||||||
|
|
||||||
|
# Enforce FIPS-like limits on using hash algorithms for cryptographic purposes.
|
||||||
|
# Will disable MD5 & SHA1 FP sigs and will require '.sign' files to verify
|
||||||
|
# CVD authenticity.
|
||||||
|
# Default: no
|
||||||
|
#FIPSCryptoHashLimits yes
|
||||||
|
|
||||||
# Path to the log file (make sure it has proper permissions)
|
# Path to the log file (make sure it has proper permissions)
|
||||||
# Default: disabled
|
# Default: disabled
|
||||||
#UpdateLogFile /var/log/freshclam.log
|
#UpdateLogFile /var/log/freshclam.log
|
||||||
|
|
|
@ -73,6 +73,23 @@ else()
|
||||||
install(TARGETS ex_file_inspection_callback DESTINATION ${CMAKE_INSTALL_BINDIR})
|
install(TARGETS ex_file_inspection_callback DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
add_executable(ex_scan_callbacks)
|
||||||
|
target_sources(ex_scan_callbacks
|
||||||
|
PRIVATE ex_scan_callbacks.c)
|
||||||
|
set_target_properties(ex_scan_callbacks PROPERTIES COMPILE_FLAGS "${WARNCFLAGS}")
|
||||||
|
target_link_libraries(ex_scan_callbacks
|
||||||
|
PRIVATE
|
||||||
|
ClamAV::libclamav)
|
||||||
|
if(LLVM_FOUND)
|
||||||
|
target_link_directories( ex_scan_callbacks PUBLIC ${LLVM_LIBRARY_DIRS} )
|
||||||
|
target_link_libraries( ex_scan_callbacks PUBLIC ${LLVM_LIBRARIES} )
|
||||||
|
endif()
|
||||||
|
if(WIN32)
|
||||||
|
install(TARGETS ex_scan_callbacks DESTINATION .)
|
||||||
|
else()
|
||||||
|
install(TARGETS ex_scan_callbacks DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||||
|
endif()
|
||||||
|
|
||||||
add_executable(ex_cl_cvdunpack)
|
add_executable(ex_cl_cvdunpack)
|
||||||
target_sources(ex_cl_cvdunpack
|
target_sources(ex_cl_cvdunpack
|
||||||
PRIVATE ex_cl_cvdunpack.c)
|
PRIVATE ex_cl_cvdunpack.c)
|
||||||
|
|
|
@ -45,7 +45,7 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
const char *filename;
|
const char *filename;
|
||||||
const char *destination_directory;
|
const char *destination_directory;
|
||||||
bool dont_verify = false;
|
uint32_t dboptions = 0;
|
||||||
|
|
||||||
switch (argc) {
|
switch (argc) {
|
||||||
case 2:
|
case 2:
|
||||||
|
@ -60,7 +60,7 @@ int main(int argc, char **argv)
|
||||||
if (strcmp(argv[1], "--no-verify") == 0) {
|
if (strcmp(argv[1], "--no-verify") == 0) {
|
||||||
filename = argv[2];
|
filename = argv[2];
|
||||||
destination_directory = argv[3];
|
destination_directory = argv[3];
|
||||||
dont_verify = true;
|
dboptions = CL_DB_UNSIGNED;
|
||||||
} else {
|
} else {
|
||||||
printf("Usage: %s [--no-verify] file [destination_directory]\n", argv[0]);
|
printf("Usage: %s [--no-verify] file [destination_directory]\n", argv[0]);
|
||||||
return CL_EARG;
|
return CL_EARG;
|
||||||
|
@ -73,7 +73,7 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
// Note: using NULL for certs_directory will disable external digital signature verification.
|
// Note: using NULL for certs_directory will disable external digital signature verification.
|
||||||
|
|
||||||
ret = cl_cvdunpack_ex(filename, destination_directory, dont_verify, NULL);
|
ret = cl_cvdunpack_ex(filename, destination_directory, NULL, dboptions);
|
||||||
if (ret != CL_SUCCESS) {
|
if (ret != CL_SUCCESS) {
|
||||||
printf("ERROR: %s\n", cl_strerror(ret));
|
printf("ERROR: %s\n", cl_strerror(ret));
|
||||||
}
|
}
|
||||||
|
|
1498
examples/ex_scan_callbacks.c
Normal file
1498
examples/ex_scan_callbacks.c
Normal file
File diff suppressed because it is too large
Load diff
|
@ -1003,6 +1003,8 @@ static fc_error_t initialize(struct optstruct *opts)
|
||||||
|
|
||||||
fcConfig.bCompressLocalDatabase = optget(opts, "CompressLocalDatabase")->enabled;
|
fcConfig.bCompressLocalDatabase = optget(opts, "CompressLocalDatabase")->enabled;
|
||||||
|
|
||||||
|
fcConfig.bFipsLimits = optget(opts, "FIPSCryptoHashLimits")->enabled;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Initialize libfreshclam.
|
* Initialize libfreshclam.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -55,7 +55,7 @@ void XzCheck_Init(CXzCheck *p, int mode)
|
||||||
case XZ_CHECK_CRC32: p->crc = CRC_INIT_VAL; break;
|
case XZ_CHECK_CRC32: p->crc = CRC_INIT_VAL; break;
|
||||||
case XZ_CHECK_CRC64: p->crc64 = CRC64_INIT_VAL; break;
|
case XZ_CHECK_CRC64: p->crc64 = CRC64_INIT_VAL; break;
|
||||||
case XZ_CHECK_SHA256:
|
case XZ_CHECK_SHA256:
|
||||||
p->sha = cl_hash_init("sha256");
|
p->sha = cl_hash_init("sha2-256");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -701,7 +701,7 @@ SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen,
|
||||||
{
|
{
|
||||||
RINOK(Xz_ParseHeader(&p->streamFlags, p->buf));
|
RINOK(Xz_ParseHeader(&p->streamFlags, p->buf));
|
||||||
p->state = XZ_STATE_BLOCK_HEADER;
|
p->state = XZ_STATE_BLOCK_HEADER;
|
||||||
p->sha = cl_hash_init("sha256");
|
p->sha = cl_hash_init("sha2-256");
|
||||||
p->indexSize = 0;
|
p->indexSize = 0;
|
||||||
p->numBlocks = 0;
|
p->numBlocks = 0;
|
||||||
p->pos = 0;
|
p->pos = 0;
|
||||||
|
@ -722,7 +722,7 @@ SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen,
|
||||||
p->indexSize += p->indexPreSize;
|
p->indexSize += p->indexPreSize;
|
||||||
if ((p->sha)) {
|
if ((p->sha)) {
|
||||||
cl_finish_hash(p->sha, p->shaDigest);
|
cl_finish_hash(p->sha, p->shaDigest);
|
||||||
p->sha = cl_hash_init("sha256");
|
p->sha = cl_hash_init("sha2-256");
|
||||||
}
|
}
|
||||||
p->crc = CrcUpdate(CRC_INIT_VAL, p->buf, p->indexPreSize);
|
p->crc = CrcUpdate(CRC_INIT_VAL, p->buf, p->indexPreSize);
|
||||||
p->state = XZ_STATE_STREAM_INDEX;
|
p->state = XZ_STATE_STREAM_INDEX;
|
||||||
|
|
|
@ -180,7 +180,7 @@ int cli_7unz(cli_ctx *ctx, size_t offset)
|
||||||
else if ((outBuffer == NULL) || (outSizeProcessed == 0)) {
|
else if ((outBuffer == NULL) || (outSizeProcessed == 0)) {
|
||||||
cli_dbgmsg("cli_unz: extracted empty file\n");
|
cli_dbgmsg("cli_unz: extracted empty file\n");
|
||||||
} else {
|
} else {
|
||||||
if ((found = cli_gentempfd(ctx->sub_tmpdir, &tmp_name, &fd)))
|
if ((found = cli_gentempfd(ctx->this_layer_tmpdir, &tmp_name, &fd)))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
cli_dbgmsg("cli_7unz: Saving to %s\n", tmp_name);
|
cli_dbgmsg("cli_7unz: Saving to %s\n", tmp_name);
|
||||||
|
|
|
@ -233,6 +233,7 @@ set(LIBCLAMAV_SOURCES
|
||||||
mpool.c mpool.h
|
mpool.c mpool.h
|
||||||
others.c
|
others.c
|
||||||
perflogging.c perflogging.h
|
perflogging.c perflogging.h
|
||||||
|
scan_layer.c scan_layer.h
|
||||||
scanners.c scanners.h
|
scanners.c scanners.h
|
||||||
textdet.c textdet.h
|
textdet.c textdet.h
|
||||||
version.c
|
version.c
|
||||||
|
@ -476,6 +477,10 @@ if(ENABLE_SHARED_LIB)
|
||||||
endif()
|
endif()
|
||||||
if(UNIX AND NOT APPLE AND NOT AIX)
|
if(UNIX AND NOT APPLE AND NOT AIX)
|
||||||
target_link_options( clamav PRIVATE "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/libclamav.map")
|
target_link_options( clamav PRIVATE "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/libclamav.map")
|
||||||
|
if(${CMAKE_SYSTEM_NAME} MATCHES "SunOS")
|
||||||
|
# Solaris 11.4 linker supports a subset of GNU ld version scripts, but requires a special option to enable
|
||||||
|
target_link_options( clamav PRIVATE "-Wl,-z,gnu-version-script-compat")
|
||||||
|
endif()
|
||||||
endif()
|
endif()
|
||||||
if(WIN32)
|
if(WIN32)
|
||||||
install( TARGETS clamav DESTINATION . COMPONENT libraries )
|
install( TARGETS clamav DESTINATION . COMPONENT libraries )
|
||||||
|
|
|
@ -106,7 +106,7 @@
|
||||||
#define OID_1_3_6_1_4_1_311_12_1_2 "\x2b\x06\x01\x04\x01\x82\x37\x0c\x01\x02"
|
#define OID_1_3_6_1_4_1_311_12_1_2 "\x2b\x06\x01\x04\x01\x82\x37\x0c\x01\x02"
|
||||||
#define OID_szOID_CATALOG_LIST_MEMBER OID_1_3_6_1_4_1_311_12_1_2
|
#define OID_szOID_CATALOG_LIST_MEMBER OID_1_3_6_1_4_1_311_12_1_2
|
||||||
|
|
||||||
/* CATALOG_LIST_MEMBER2 seems to be what's used by the SHA256-based CAT files */
|
/* CATALOG_LIST_MEMBER2 seems to be what's used by the SHA2-256-based CAT files */
|
||||||
#define OID_1_3_6_1_4_1_311_12_1_3 "\x2b\x06\x01\x04\x01\x82\x37\x0c\x01\x03"
|
#define OID_1_3_6_1_4_1_311_12_1_3 "\x2b\x06\x01\x04\x01\x82\x37\x0c\x01\x03"
|
||||||
#define OID_szOID_CATALOG_LIST_MEMBER2 OID_1_3_6_1_4_1_311_12_1_3
|
#define OID_szOID_CATALOG_LIST_MEMBER2 OID_1_3_6_1_4_1_311_12_1_3
|
||||||
|
|
||||||
|
@ -154,31 +154,31 @@ static int map_raw(fmap_t *map, const void *data, unsigned int len, uint8_t raw[
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int map_sha512(fmap_t *map, const void *data, unsigned int len, uint8_t sha512[SHA512_HASH_SIZE])
|
static int map_sha2_512(fmap_t *map, const void *data, unsigned int len, uint8_t sha2_512[SHA512_HASH_SIZE])
|
||||||
{
|
{
|
||||||
if (!fmap_need_ptr_once(map, data, len)) {
|
if (!fmap_need_ptr_once(map, data, len)) {
|
||||||
cli_dbgmsg("map_sha512: failed to read hash data\n");
|
cli_dbgmsg("map_sha2_512: failed to read hash data\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return (cl_sha512(data, len, sha512, NULL) == NULL);
|
return (cl_sha512(data, len, sha2_512, NULL) == NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int map_sha384(fmap_t *map, const void *data, unsigned int len, uint8_t sha384[SHA384_HASH_SIZE])
|
static int map_sha2_384(fmap_t *map, const void *data, unsigned int len, uint8_t sha2_384[SHA384_HASH_SIZE])
|
||||||
{
|
{
|
||||||
if (!fmap_need_ptr_once(map, data, len)) {
|
if (!fmap_need_ptr_once(map, data, len)) {
|
||||||
cli_dbgmsg("map_sha384: failed to read hash data\n");
|
cli_dbgmsg("map_sha2_384: failed to read hash data\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return (cl_sha384(data, len, sha384, NULL) == NULL);
|
return (cl_sha384(data, len, sha2_384, NULL) == NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int map_sha256(fmap_t *map, const void *data, unsigned int len, uint8_t sha256[SHA256_HASH_SIZE])
|
static int map_sha2_256(fmap_t *map, const void *data, unsigned int len, uint8_t sha2_256[SHA256_HASH_SIZE])
|
||||||
{
|
{
|
||||||
if (!fmap_need_ptr_once(map, data, len)) {
|
if (!fmap_need_ptr_once(map, data, len)) {
|
||||||
cli_dbgmsg("map_sha256: failed to read hash data\n");
|
cli_dbgmsg("map_sha2_256: failed to read hash data\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return (cl_sha256(data, len, sha256, NULL) == NULL);
|
return (cl_sha256(data, len, sha2_256, NULL) == NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int map_sha1(fmap_t *map, const void *data, unsigned int len, uint8_t sha1[SHA1_HASH_SIZE])
|
static int map_sha1(fmap_t *map, const void *data, unsigned int len, uint8_t sha1[SHA1_HASH_SIZE])
|
||||||
|
@ -211,15 +211,15 @@ static int map_hash(fmap_t *map, const void *data, unsigned int len, uint8_t *ou
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
} else if (hashtype == CLI_SHA256RSA) {
|
} else if (hashtype == CLI_SHA256RSA) {
|
||||||
if (map_sha256(map, data, len, out_hash)) {
|
if (map_sha2_256(map, data, len, out_hash)) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
} else if (hashtype == CLI_SHA384RSA) {
|
} else if (hashtype == CLI_SHA384RSA) {
|
||||||
if (map_sha384(map, data, len, out_hash)) {
|
if (map_sha2_384(map, data, len, out_hash)) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
} else if (hashtype == CLI_SHA512RSA) {
|
} else if (hashtype == CLI_SHA512RSA) {
|
||||||
if (map_sha512(map, data, len, out_hash)) {
|
if (map_sha2_512(map, data, len, out_hash)) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -237,11 +237,11 @@ static void *get_hash_ctx(cli_crt_hashtype hashtype)
|
||||||
} else if (hashtype == CLI_MD5RSA) {
|
} else if (hashtype == CLI_MD5RSA) {
|
||||||
ctx = cl_hash_init("md5");
|
ctx = cl_hash_init("md5");
|
||||||
} else if (hashtype == CLI_SHA256RSA) {
|
} else if (hashtype == CLI_SHA256RSA) {
|
||||||
ctx = cl_hash_init("sha256");
|
ctx = cl_hash_init("sha2-256");
|
||||||
} else if (hashtype == CLI_SHA384RSA) {
|
} else if (hashtype == CLI_SHA384RSA) {
|
||||||
ctx = cl_hash_init("sha384");
|
ctx = cl_hash_init("sha2-384");
|
||||||
} else if (hashtype == CLI_SHA512RSA) {
|
} else if (hashtype == CLI_SHA512RSA) {
|
||||||
ctx = cl_hash_init("sha512");
|
ctx = cl_hash_init("sha2-512");
|
||||||
} else {
|
} else {
|
||||||
cli_dbgmsg("asn1_get_hash_ctx: unsupported hashtype\n");
|
cli_dbgmsg("asn1_get_hash_ctx: unsupported hashtype\n");
|
||||||
}
|
}
|
||||||
|
@ -526,7 +526,7 @@ static int asn1_getnum(const char *s)
|
||||||
return (s[0] - '0') * 10 + (s[1] - '0');
|
return (s[0] - '0') * 10 + (s[1] - '0');
|
||||||
}
|
}
|
||||||
|
|
||||||
static int asn1_get_time(fmap_t *map, const void **asn1data, unsigned int *size, time_t *tm)
|
static int asn1_get_time(fmap_t *map, const void **asn1data, unsigned int *size, int64_t *tm)
|
||||||
{
|
{
|
||||||
struct cli_asn1 obj;
|
struct cli_asn1 obj;
|
||||||
int ret = asn1_get_obj(map, *asn1data, size, &obj);
|
int ret = asn1_get_obj(map, *asn1data, size, &obj);
|
||||||
|
@ -1134,7 +1134,7 @@ static int asn1_get_x509(fmap_t *map, const void **asn1data, unsigned int *size,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int asn1_parse_countersignature(fmap_t *map, const void **asn1data, unsigned int *size, crtmgr *cmgr, const uint8_t *message, const unsigned int message_size, time_t not_before, time_t not_after)
|
static int asn1_parse_countersignature(fmap_t *map, const void **asn1data, unsigned int *size, crtmgr *cmgr, const uint8_t *message, const unsigned int message_size, int64_t not_before, int64_t not_after)
|
||||||
{
|
{
|
||||||
|
|
||||||
struct cli_asn1 asn1, deep, deeper;
|
struct cli_asn1 asn1, deep, deeper;
|
||||||
|
@ -1311,7 +1311,7 @@ static int asn1_parse_countersignature(fmap_t *map, const void **asn1data, unsig
|
||||||
break;
|
break;
|
||||||
case 2: /* signingTime */
|
case 2: /* signingTime */
|
||||||
{
|
{
|
||||||
time_t sigdate; /* FIXME shall i use it?! */
|
int64_t sigdate; /* FIXME shall i use it?! */
|
||||||
if (asn1_get_time(map, &deeper.content, &deep.size, &sigdate)) {
|
if (asn1_get_time(map, &deeper.content, &deep.size, &sigdate)) {
|
||||||
cli_dbgmsg("asn1_parse_countersignature: an error occurred when getting the time\n");
|
cli_dbgmsg("asn1_parse_countersignature: an error occurred when getting the time\n");
|
||||||
deep.size = 1;
|
deep.size = 1;
|
||||||
|
@ -2293,9 +2293,9 @@ int asn1_load_mscat(fmap_t *map, struct cl_engine *engine)
|
||||||
if (CLI_SHA1RSA == hashtype) {
|
if (CLI_SHA1RSA == hashtype) {
|
||||||
hm_hashtype = CLI_HASH_SHA1;
|
hm_hashtype = CLI_HASH_SHA1;
|
||||||
} else if (CLI_SHA256RSA == hashtype) {
|
} else if (CLI_SHA256RSA == hashtype) {
|
||||||
hm_hashtype = CLI_HASH_SHA256;
|
hm_hashtype = CLI_HASH_SHA2_256;
|
||||||
} else {
|
} else {
|
||||||
cli_dbgmsg("asn1_load_mscat: only SHA1 and SHA256 hashes are supported for .cat file sigs\n");
|
cli_dbgmsg("asn1_load_mscat: only SHA1 and SHA2-256 hashes are supported for .cat file sigs\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2333,7 +2333,7 @@ int asn1_load_mscat(fmap_t *map, struct cl_engine *engine)
|
||||||
/* Load the trusted hashes into hm_fp, using the size values
|
/* Load the trusted hashes into hm_fp, using the size values
|
||||||
* 1 and 2 as sentinel values corresponding to CAB and PE hashes
|
* 1 and 2 as sentinel values corresponding to CAB and PE hashes
|
||||||
* from .cat files respectively. */
|
* from .cat files respectively. */
|
||||||
if (hm_addhash_bin(engine->hm_fp, tagval3.content, hm_hashtype, hashed_obj_type, NULL)) {
|
if (CL_SUCCESS != hm_addhash_bin(engine, HASH_PURPOSE_WHOLE_FILE_FP_CHECK, tagval3.content, hm_hashtype, hashed_obj_type, NULL)) {
|
||||||
cli_warnmsg("asn1_load_mscat: failed to add hash\n");
|
cli_warnmsg("asn1_load_mscat: failed to add hash\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -2440,5 +2440,9 @@ cl_error_t asn1_check_mscat(struct cl_engine *engine, fmap_t *map, size_t offset
|
||||||
}
|
}
|
||||||
|
|
||||||
cli_dbgmsg("asn1_check_mscat: file with valid authenticode signature, trusted\n");
|
cli_dbgmsg("asn1_check_mscat: file with valid authenticode signature, trusted\n");
|
||||||
|
|
||||||
|
// Remove any evidence for this layer and set the verdict to trusted.
|
||||||
|
(void)cli_trust_this_layer(ctx, "authenticode digital signature verification");
|
||||||
|
|
||||||
return CL_VERIFIED;
|
return CL_VERIFIED;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1638,7 +1638,7 @@ cl_error_t cli_scanautoit(cli_ctx *ctx, off_t offset)
|
||||||
if (!(version = fmap_need_off_once(map, offset, sizeof(*version))))
|
if (!(version = fmap_need_off_once(map, offset, sizeof(*version))))
|
||||||
return CL_EREAD;
|
return CL_EREAD;
|
||||||
|
|
||||||
if (!(tmpd = cli_gentemp_with_prefix(ctx->sub_tmpdir, "autoit-tmp")))
|
if (!(tmpd = cli_gentemp_with_prefix(ctx->this_layer_tmpdir, "autoit-tmp")))
|
||||||
return CL_ETMPDIR;
|
return CL_ETMPDIR;
|
||||||
if (mkdir(tmpd, 0700)) {
|
if (mkdir(tmpd, 0700)) {
|
||||||
cli_dbgmsg("autoit: Can't create temporary directory %s\n", tmpd);
|
cli_dbgmsg("autoit: Can't create temporary directory %s\n", tmpd);
|
||||||
|
|
|
@ -68,10 +68,10 @@ int cli_binhex(cli_ctx *ctx)
|
||||||
cli_dbgmsg("in cli_binhex\n");
|
cli_dbgmsg("in cli_binhex\n");
|
||||||
if (!map->len) return CL_CLEAN;
|
if (!map->len) return CL_CLEAN;
|
||||||
|
|
||||||
if ((ret = cli_gentempfd(ctx->sub_tmpdir, &dname, &datafd)) != CL_SUCCESS)
|
if ((ret = cli_gentempfd(ctx->this_layer_tmpdir, &dname, &datafd)) != CL_SUCCESS)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if ((ret = cli_gentempfd(ctx->sub_tmpdir, &rname, &resfd)) != CL_SUCCESS) {
|
if ((ret = cli_gentempfd(ctx->this_layer_tmpdir, &rname, &resfd)) != CL_SUCCESS) {
|
||||||
close(datafd);
|
close(datafd);
|
||||||
if (cli_unlink(dname)) ret = CL_EUNLINK;
|
if (cli_unlink(dname)) ret = CL_EUNLINK;
|
||||||
free(dname);
|
free(dname);
|
||||||
|
|
|
@ -518,7 +518,7 @@ void fileblobPartialSet(fileblob *fb, const char *fullname, const char *arg)
|
||||||
close(fb->fd);
|
close(fb->fd);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
blobSetFilename(&fb->b, fb->ctx ? fb->ctx->sub_tmpdir : NULL, fullname);
|
blobSetFilename(&fb->b, fb->ctx ? fb->ctx->this_layer_tmpdir : NULL, fullname);
|
||||||
if (fb->b.data)
|
if (fb->b.data)
|
||||||
if (fileblobAddData(fb, fb->b.data, fb->b.len) == 0) {
|
if (fileblobAddData(fb, fb->b.data, fb->b.len) == 0) {
|
||||||
free(fb->b.data);
|
free(fb->b.data);
|
||||||
|
@ -594,8 +594,8 @@ int fileblobAddData(fileblob *fb, const unsigned char *data, size_t len)
|
||||||
do_scan = 0;
|
do_scan = 0;
|
||||||
if (do_scan) {
|
if (do_scan) {
|
||||||
if (ctx->scanned)
|
if (ctx->scanned)
|
||||||
*ctx->scanned += (unsigned long)len / CL_COUNT_PRECISION;
|
*ctx->scanned += len;
|
||||||
fb->bytes_scanned += (unsigned long)len;
|
fb->bytes_scanned += len;
|
||||||
|
|
||||||
if ((len > 5) && cli_updatelimits(ctx, len) == CL_CLEAN && (cli_scan_buff(data, (unsigned int)len, 0, ctx->virname, ctx->engine, CL_TYPE_BINARY_DATA, NULL) == CL_VIRUS)) {
|
if ((len > 5) && cli_updatelimits(ctx, len) == CL_CLEAN && (cli_scan_buff(data, (unsigned int)len, 0, ctx->virname, ctx->engine, CL_TYPE_BINARY_DATA, NULL) == CL_VIRUS)) {
|
||||||
fb->isInfected = 1;
|
fb->isInfected = 1;
|
||||||
|
|
|
@ -62,7 +62,7 @@ typedef struct fileblob {
|
||||||
*/
|
*/
|
||||||
char *fullname; /* full pathname of the file */
|
char *fullname; /* full pathname of the file */
|
||||||
cli_ctx *ctx; /* When set we can scan the blob, otherwise NULL */
|
cli_ctx *ctx; /* When set we can scan the blob, otherwise NULL */
|
||||||
unsigned long bytes_scanned;
|
uint64_t bytes_scanned;
|
||||||
unsigned int isNotEmpty : 1;
|
unsigned int isNotEmpty : 1;
|
||||||
unsigned int isInfected : 1;
|
unsigned int isInfected : 1;
|
||||||
} fileblob;
|
} fileblob;
|
||||||
|
|
|
@ -142,13 +142,13 @@ static void bytecode_context_reset(struct cli_bc_ctx *ctx)
|
||||||
fd = open(fullname, O_RDONLY | O_BINARY);
|
fd = open(fullname, O_RDONLY | O_BINARY);
|
||||||
if (fd >= 0) {
|
if (fd >= 0) {
|
||||||
ret = cli_scan_desc(fd, cctx, CL_TYPE_HTML, false, NULL, AC_SCAN_VIR,
|
ret = cli_scan_desc(fd, cctx, CL_TYPE_HTML, false, NULL, AC_SCAN_VIR,
|
||||||
NULL, NULL, LAYER_ATTRIBUTES_NORMALIZED);
|
NULL, "javascript-as-html", fullname, LAYER_ATTRIBUTES_NORMALIZED);
|
||||||
if (ret == CL_CLEAN) {
|
if (ret == CL_CLEAN) {
|
||||||
if (lseek(fd, 0, SEEK_SET) == -1)
|
if (lseek(fd, 0, SEEK_SET) == -1)
|
||||||
cli_dbgmsg("cli_bytecode: call to lseek() has failed\n");
|
cli_dbgmsg("cli_bytecode: call to lseek() has failed\n");
|
||||||
else {
|
else {
|
||||||
ret = cli_scan_desc(fd, cctx, CL_TYPE_TEXT_ASCII, false, NULL, AC_SCAN_VIR,
|
ret = cli_scan_desc(fd, cctx, CL_TYPE_TEXT_ASCII, false, NULL, AC_SCAN_VIR,
|
||||||
NULL, NULL, LAYER_ATTRIBUTES_NORMALIZED);
|
NULL, "javascript-as-text-ascii", fullname, LAYER_ATTRIBUTES_NORMALIZED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
close(fd);
|
close(fd);
|
||||||
|
|
|
@ -215,7 +215,7 @@ int32_t cli_bcapi_write(struct cli_bc_ctx *ctx, uint8_t *data, int32_t len)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (-1 == ctx->outfd) {
|
if (-1 == ctx->outfd) {
|
||||||
ctx->tempfile = cli_gentemp_with_prefix(cctx ? cctx->sub_tmpdir : NULL, "bcapi_write");
|
ctx->tempfile = cli_gentemp_with_prefix(cctx ? cctx->this_layer_tmpdir : NULL, "bcapi_write");
|
||||||
if (!ctx->tempfile) {
|
if (!ctx->tempfile) {
|
||||||
cli_dbgmsg("Bytecode API: Unable to allocate memory for tempfile\n");
|
cli_dbgmsg("Bytecode API: Unable to allocate memory for tempfile\n");
|
||||||
cli_event_error_oom(EV, 0);
|
cli_event_error_oom(EV, 0);
|
||||||
|
@ -1737,7 +1737,7 @@ int32_t cli_bcapi_input_switch(struct cli_bc_ctx *ctx, int32_t extracted_file)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Free the fmap used for the extracted file */
|
/* Free the fmap used for the extracted file */
|
||||||
funmap(ctx->fmap);
|
fmap_free(ctx->fmap);
|
||||||
|
|
||||||
/* Restore pointer to original fmap */
|
/* Restore pointer to original fmap */
|
||||||
cli_bytecode_context_setfile(ctx, ctx->save_map);
|
cli_bytecode_context_setfile(ctx, ctx->save_map);
|
||||||
|
@ -1761,7 +1761,7 @@ int32_t cli_bcapi_input_switch(struct cli_bc_ctx *ctx, int32_t extracted_file)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create fmap for the extracted file */
|
/* Create fmap for the extracted file */
|
||||||
map = fmap(ctx->outfd, 0, 0, NULL);
|
map = fmap_new(ctx->outfd, 0, 0, NULL, ctx->tempfile);
|
||||||
if (!map) {
|
if (!map) {
|
||||||
cli_warnmsg("can't mmap() extracted temporary file %s\n", ctx->tempfile);
|
cli_warnmsg("can't mmap() extracted temporary file %s\n", ctx->tempfile);
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -2006,7 +2006,7 @@ int32_t cli_bcapi_get_file_reliability(struct cli_bc_ctx *ctx)
|
||||||
int32_t cli_bcapi_json_is_active(struct cli_bc_ctx *ctx)
|
int32_t cli_bcapi_json_is_active(struct cli_bc_ctx *ctx)
|
||||||
{
|
{
|
||||||
cli_ctx *cctx = (cli_ctx *)ctx->ctx;
|
cli_ctx *cctx = (cli_ctx *)ctx->ctx;
|
||||||
if (cctx->properties != NULL) {
|
if (cctx->metadata_json != NULL) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -2025,7 +2025,7 @@ static int32_t cli_bcapi_json_objs_init(struct cli_bc_ctx *ctx)
|
||||||
}
|
}
|
||||||
ctx->jsonobjs = (void **)j;
|
ctx->jsonobjs = (void **)j;
|
||||||
ctx->njsonobjs = n;
|
ctx->njsonobjs = n;
|
||||||
j[n - 1] = cctx->properties;
|
j[n - 1] = cctx->metadata_json;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,7 @@ static inline unsigned int getkey(uint8_t *hash, size_t trees)
|
||||||
|
|
||||||
/* SPLAY --------------------------------------------------------------------- */
|
/* SPLAY --------------------------------------------------------------------- */
|
||||||
struct node { /* a node */
|
struct node { /* a node */
|
||||||
int64_t digest[2];
|
int64_t digest[4];
|
||||||
struct node *left;
|
struct node *left;
|
||||||
struct node *right;
|
struct node *right;
|
||||||
struct node *up;
|
struct node *up;
|
||||||
|
@ -201,7 +201,7 @@ static void printnode(const char *prefix, struct cache_set *cs, struct node *n)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
printf("%s node [%02u]:", prefix, n - cs->data);
|
printf("%s node [%02u]:", prefix, n - cs->data);
|
||||||
printf(" size=%lu digest=%llx,%llx\n", (unsigned long)(n->size), n->digest[0], n->digest[1]);
|
printf(" size=%lu digest=%llx,%llx,%llx,%llx\n", (unsigned long)(n->size), n->digest[0], n->digest[1], n->digest[2], n->digest[3]);
|
||||||
printf("\tleft=");
|
printf("\tleft=");
|
||||||
if (n->left)
|
if (n->left)
|
||||||
printf("%02u ", n->left - cs->data);
|
printf("%02u ", n->left - cs->data);
|
||||||
|
@ -265,7 +265,7 @@ static inline void printchain(const char *prefix, struct cache_set *cs)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Looks up a node and splays it up to the root of the tree */
|
/* Looks up a node and splays it up to the root of the tree */
|
||||||
static int splay(int64_t *md5, size_t len, struct cache_set *cs)
|
static int splay(int64_t *sha2_256, size_t len, struct cache_set *cs)
|
||||||
{
|
{
|
||||||
struct node next = {{0, 0}, NULL, NULL, NULL, NULL, NULL, 0, 0}, *right = &next, *left = &next, *temp, *root = cs->root;
|
struct node next = {{0, 0}, NULL, NULL, NULL, NULL, NULL, 0, 0}, *right = &next, *left = &next, *temp, *root = cs->root;
|
||||||
int comp, found = 0;
|
int comp, found = 0;
|
||||||
|
@ -274,10 +274,10 @@ static int splay(int64_t *md5, size_t len, struct cache_set *cs)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
comp = cmp(md5, len, root->digest, root->size);
|
comp = cmp(sha2_256, len, root->digest, root->size);
|
||||||
if (comp < 0) {
|
if (comp < 0) {
|
||||||
if (!root->left) break;
|
if (!root->left) break;
|
||||||
if (cmp(md5, len, root->left->digest, root->left->size) < 0) {
|
if (cmp(sha2_256, len, root->left->digest, root->left->size) < 0) {
|
||||||
temp = root->left;
|
temp = root->left;
|
||||||
root->left = temp->right;
|
root->left = temp->right;
|
||||||
if (temp->right) temp->right->up = root;
|
if (temp->right) temp->right->up = root;
|
||||||
|
@ -292,7 +292,7 @@ static int splay(int64_t *md5, size_t len, struct cache_set *cs)
|
||||||
root = root->left;
|
root = root->left;
|
||||||
} else if (comp > 0) {
|
} else if (comp > 0) {
|
||||||
if (!root->right) break;
|
if (!root->right) break;
|
||||||
if (cmp(md5, len, root->right->digest, root->right->size) > 0) {
|
if (cmp(sha2_256, len, root->right->digest, root->right->size) > 0) {
|
||||||
temp = root->right;
|
temp = root->right;
|
||||||
root->right = temp->left;
|
root->right = temp->left;
|
||||||
if (temp->left) temp->left->up = root;
|
if (temp->left) temp->left->up = root;
|
||||||
|
@ -325,11 +325,11 @@ static int splay(int64_t *md5, size_t len, struct cache_set *cs)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Looks up an hash in the tree and maintains the replacement chain */
|
/* Looks up an hash in the tree and maintains the replacement chain */
|
||||||
static inline int cacheset_lookup(struct cache_set *cs, unsigned char *md5, size_t size, uint32_t recursion_level)
|
static inline int cacheset_lookup(struct cache_set *cs, uint8_t *sha2_256, size_t size, uint32_t recursion_level)
|
||||||
{
|
{
|
||||||
int64_t hash[2];
|
int64_t hash[4];
|
||||||
|
|
||||||
memcpy(hash, md5, 16);
|
memcpy(hash, sha2_256, 32);
|
||||||
if (splay(hash, size, cs)) {
|
if (splay(hash, size, cs)) {
|
||||||
struct node *o = cs->root->prev, *p = cs->root, *q = cs->root->next;
|
struct node *o = cs->root->prev, *p = cs->root, *q = cs->root->next;
|
||||||
#ifdef PRINT_CHAINS
|
#ifdef PRINT_CHAINS
|
||||||
|
@ -367,12 +367,12 @@ static inline int cacheset_lookup(struct cache_set *cs, unsigned char *md5, size
|
||||||
/* If the hash is present nothing happens.
|
/* If the hash is present nothing happens.
|
||||||
Otherwise a new node is created for the hash picking one from the begin of the chain.
|
Otherwise a new node is created for the hash picking one from the begin of the chain.
|
||||||
Used nodes are moved to the end of the chain */
|
Used nodes are moved to the end of the chain */
|
||||||
static inline const char *cacheset_add(struct cache_set *cs, unsigned char *md5, size_t size, uint32_t recursion_level)
|
static inline const char *cacheset_add(struct cache_set *cs, uint8_t *sha2_256, size_t size, uint32_t recursion_level)
|
||||||
{
|
{
|
||||||
struct node *newnode;
|
struct node *newnode;
|
||||||
int64_t hash[2];
|
int64_t hash[4];
|
||||||
|
|
||||||
memcpy(hash, md5, 16);
|
memcpy(hash, sha2_256, 32);
|
||||||
if (splay(hash, size, cs)) {
|
if (splay(hash, size, cs)) {
|
||||||
if (cs->root->minrec > recursion_level)
|
if (cs->root->minrec > recursion_level)
|
||||||
cs->root->minrec = recursion_level;
|
cs->root->minrec = recursion_level;
|
||||||
|
@ -457,13 +457,13 @@ static inline const char *cacheset_add(struct cache_set *cs, unsigned char *md5,
|
||||||
/* If the hash is not present nothing happens other than splaying the tree.
|
/* If the hash is not present nothing happens other than splaying the tree.
|
||||||
Otherwise the identified node is removed from the tree and then placed back at
|
Otherwise the identified node is removed from the tree and then placed back at
|
||||||
the front of the chain. */
|
the front of the chain. */
|
||||||
static inline void cacheset_remove(struct cache_set *cs, unsigned char *md5, size_t size)
|
static inline void cacheset_remove(struct cache_set *cs, uint8_t *sha2_256, size_t size)
|
||||||
{
|
{
|
||||||
struct node *targetnode;
|
struct node *targetnode;
|
||||||
struct node *reattachnode;
|
struct node *reattachnode;
|
||||||
int64_t hash[2];
|
int64_t hash[4];
|
||||||
|
|
||||||
memcpy(hash, md5, 16);
|
memcpy(hash, sha2_256, 32);
|
||||||
if (splay(hash, size, cs) != 1) {
|
if (splay(hash, size, cs) != 1) {
|
||||||
cli_dbgmsg("cacheset_remove: node not found in tree\n");
|
cli_dbgmsg("cacheset_remove: node not found in tree\n");
|
||||||
return; /* No op */
|
return; /* No op */
|
||||||
|
@ -498,6 +498,8 @@ static inline void cacheset_remove(struct cache_set *cs, unsigned char *md5, siz
|
||||||
targetnode->size = (size_t)0;
|
targetnode->size = (size_t)0;
|
||||||
targetnode->digest[0] = 0;
|
targetnode->digest[0] = 0;
|
||||||
targetnode->digest[1] = 0;
|
targetnode->digest[1] = 0;
|
||||||
|
targetnode->digest[2] = 0;
|
||||||
|
targetnode->digest[3] = 0;
|
||||||
targetnode->up = NULL;
|
targetnode->up = NULL;
|
||||||
targetnode->left = NULL;
|
targetnode->left = NULL;
|
||||||
targetnode->right = NULL;
|
targetnode->right = NULL;
|
||||||
|
@ -527,50 +529,56 @@ static inline void cacheset_remove(struct cache_set *cs, unsigned char *md5, siz
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Looks up an hash in the proper tree */
|
/* Looks up an hash in the proper tree */
|
||||||
static int cache_lookup_hash(unsigned char *md5, size_t len, struct CACHE *cache, uint32_t recursion_level)
|
static cl_error_t cache_lookup_hash(uint8_t *sha2_256, size_t len, struct CACHE *cache, uint32_t recursion_level)
|
||||||
{
|
{
|
||||||
|
cl_error_t ret = CL_ERROR;
|
||||||
unsigned int key = 0;
|
unsigned int key = 0;
|
||||||
int ret = CL_VIRUS;
|
|
||||||
struct CACHE *c;
|
struct CACHE *c;
|
||||||
|
|
||||||
if (!md5) {
|
if (!sha2_256) {
|
||||||
cli_dbgmsg("cache_lookup: No hash available. Nothing to look up.\n");
|
cli_dbgmsg("cache_lookup: No hash available. Nothing to look up.\n");
|
||||||
return ret;
|
ret = CL_ENULLARG;
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
key = getkey(md5, cache->trees);
|
key = getkey(sha2_256, cache->trees);
|
||||||
|
|
||||||
c = &cache[key];
|
c = &cache[key];
|
||||||
|
|
||||||
#ifdef CL_THREAD_SAFE
|
#ifdef CL_THREAD_SAFE
|
||||||
if (pthread_mutex_lock(&c->mutex)) {
|
if (pthread_mutex_lock(&c->mutex)) {
|
||||||
cli_errmsg("cache_lookup_hash: cache_lookup_hash: mutex lock fail\n");
|
cli_errmsg("cache_lookup_hash: cache_lookup_hash: mutex lock fail\n");
|
||||||
return ret;
|
ret = CL_ELOCK;
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ret = (cacheset_lookup(&c->cacheset, md5, len, recursion_level)) ? CL_CLEAN : CL_VIRUS;
|
ret = (cacheset_lookup(&c->cacheset, sha2_256, len, recursion_level)) ? CL_CLEAN : CL_VIRUS;
|
||||||
|
|
||||||
#ifdef CL_THREAD_SAFE
|
#ifdef CL_THREAD_SAFE
|
||||||
pthread_mutex_unlock(&c->mutex);
|
pthread_mutex_unlock(&c->mutex);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
done:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int clean_cache_init(struct cl_engine *engine)
|
cl_error_t clean_cache_init(struct cl_engine *engine)
|
||||||
{
|
{
|
||||||
|
cl_error_t status = CL_ERROR;
|
||||||
struct CACHE *cache;
|
struct CACHE *cache;
|
||||||
unsigned int i, j;
|
uint32_t i;
|
||||||
|
|
||||||
if (!engine) {
|
if (!engine) {
|
||||||
cli_errmsg("clean_cache_init: mpool malloc fail\n");
|
cli_errmsg("clean_cache_init: Engine is NULL.\n");
|
||||||
return 1;
|
status = CL_ENULLARG;
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (engine->engine_options & ENGINE_OPTIONS_DISABLE_CACHE) {
|
if (engine->engine_options & ENGINE_OPTIONS_DISABLE_CACHE) {
|
||||||
cli_dbgmsg("clean_cache_init: Caching disabled.\n");
|
cli_dbgmsg("clean_cache_init: Caching disabled.\n");
|
||||||
return 0;
|
status = CL_SUCCESS;
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The user requested the cache size to be engine->cache_size
|
// The user requested the cache size to be engine->cache_size
|
||||||
|
@ -583,8 +591,9 @@ int clean_cache_init(struct cl_engine *engine)
|
||||||
cli_dbgmsg("clean_cache_init: Requested cache size: %d. Actual cache size: %d. Trees: %d. Nodes per tree: %d.\n", engine->cache_size, trees * nodes_per_tree, trees, nodes_per_tree);
|
cli_dbgmsg("clean_cache_init: Requested cache size: %d. Actual cache size: %d. Trees: %d. Nodes per tree: %d.\n", engine->cache_size, trees * nodes_per_tree, trees, nodes_per_tree);
|
||||||
|
|
||||||
if (!(cache = MPOOL_MALLOC(engine->mempool, sizeof(struct CACHE) * trees))) {
|
if (!(cache = MPOOL_MALLOC(engine->mempool, sizeof(struct CACHE) * trees))) {
|
||||||
cli_errmsg("clean_cache_init: mpool malloc fail\n");
|
cli_errmsg("clean_cache_init: Failed to allocate memory for cache.\n");
|
||||||
return 1;
|
status = CL_EMEM;
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
cache->trees = trees;
|
cache->trees = trees;
|
||||||
|
@ -593,24 +602,30 @@ int clean_cache_init(struct cl_engine *engine)
|
||||||
for (i = 0; i < trees; i++) {
|
for (i = 0; i < trees; i++) {
|
||||||
#ifdef CL_THREAD_SAFE
|
#ifdef CL_THREAD_SAFE
|
||||||
if (pthread_mutex_init(&cache[i].mutex, NULL)) {
|
if (pthread_mutex_init(&cache[i].mutex, NULL)) {
|
||||||
cli_errmsg("clean_cache_init: mutex init fail\n");
|
cli_errmsg("clean_cache_init: Mutex init failed.\n");
|
||||||
for (j = 0; j < i; j++) cacheset_destroy(&cache[j].cacheset, engine->mempool);
|
status = CL_EMEM;
|
||||||
for (j = 0; j < i; j++) pthread_mutex_destroy(&cache[j].mutex);
|
goto done;
|
||||||
MPOOL_FREE(engine->mempool, cache);
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (cacheset_init(&cache[i].cacheset, engine->mempool, cache->nodes_per_tree)) {
|
if (cacheset_init(&cache[i].cacheset, engine->mempool, cache->nodes_per_tree)) {
|
||||||
for (j = 0; j < i; j++) cacheset_destroy(&cache[j].cacheset, engine->mempool);
|
cli_errmsg("clean_cache_init: Failed to initialize cache set.\n");
|
||||||
#ifdef CL_THREAD_SAFE
|
status = CL_EMEM;
|
||||||
for (j = 0; j <= i; j++) pthread_mutex_destroy(&cache[j].mutex);
|
goto done;
|
||||||
#endif
|
|
||||||
MPOOL_FREE(engine->mempool, cache);
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
engine->cache = cache;
|
engine->cache = cache;
|
||||||
return 0;
|
status = CL_SUCCESS;
|
||||||
|
|
||||||
|
done:
|
||||||
|
if (status != CL_SUCCESS) {
|
||||||
|
cli_errmsg("clean_cache_init: Failed to initialize cache.\n");
|
||||||
|
clean_cache_destroy(engine);
|
||||||
|
} else {
|
||||||
|
cli_dbgmsg("clean_cache_init: Cache initialized successfully.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
void clean_cache_destroy(struct cl_engine *engine)
|
void clean_cache_destroy(struct cl_engine *engine)
|
||||||
|
@ -634,60 +649,71 @@ void clean_cache_destroy(struct cl_engine *engine)
|
||||||
MPOOL_FREE(engine->mempool, cache);
|
MPOOL_FREE(engine->mempool, cache);
|
||||||
}
|
}
|
||||||
|
|
||||||
void clean_cache_add(unsigned char *md5, size_t size, cli_ctx *ctx)
|
void clean_cache_add(cli_ctx *ctx)
|
||||||
{
|
{
|
||||||
|
cl_error_t ret;
|
||||||
|
|
||||||
const char *errmsg = NULL;
|
const char *errmsg = NULL;
|
||||||
|
|
||||||
unsigned int key = 0;
|
unsigned int key = 0;
|
||||||
uint32_t level;
|
uint32_t level;
|
||||||
struct CACHE *c;
|
struct CACHE *c;
|
||||||
|
|
||||||
if (!ctx || !ctx->engine || !ctx->engine->cache)
|
uint8_t *sha2_256 = NULL;
|
||||||
return;
|
size_t size = 0;
|
||||||
|
|
||||||
|
if (!ctx || !ctx->engine || !ctx->engine->cache) {
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
if (ctx->engine->engine_options & ENGINE_OPTIONS_DISABLE_CACHE) {
|
if (ctx->engine->engine_options & ENGINE_OPTIONS_DISABLE_CACHE) {
|
||||||
cli_dbgmsg("clean_cache_add: Caching disabled. Not adding sample to cache.\n");
|
cli_dbgmsg("clean_cache_add: Caching disabled. Not adding sample to cache.\n");
|
||||||
return;
|
goto done;
|
||||||
}
|
|
||||||
|
|
||||||
if (!md5) {
|
|
||||||
cli_dbgmsg("clean_cache_add: No hash available. Nothing to add to cache.\n");
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SCAN_COLLECT_METADATA) {
|
if (SCAN_COLLECT_METADATA) {
|
||||||
// Don't cache when using the "collect metadata" feature.
|
// Don't cache when using the "collect metadata" feature.
|
||||||
// We don't cache the JSON, so we can't reproduce it when the cache is positive.
|
// We don't cache the JSON, so we can't reproduce it when the cache is positive.
|
||||||
cli_dbgmsg("clean_cache_add: collect metadata feature enabled, skipping cache\n");
|
cli_dbgmsg("clean_cache_add: collect metadata feature enabled, skipping cache\n");
|
||||||
return;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx->fmap && ctx->fmap->dont_cache_flag == true) {
|
if (ctx->fmap && ctx->fmap->dont_cache_flag == true) {
|
||||||
cli_dbgmsg("clean_cache_add: caching disabled for this layer, skipping cache\n");
|
cli_dbgmsg("clean_cache_add: caching disabled for this layer, skipping cache\n");
|
||||||
return;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (0 < evidence_num_alerts(ctx->evidence)) {
|
if (0 < evidence_num_alerts(ctx->this_layer_evidence)) {
|
||||||
// TODO: The dont cache flag should take care of preventing caching of files with embedded files that alert.
|
// TODO: The dont cache flag should take care of preventing caching of files with embedded files that alert.
|
||||||
// Consider removing this check to allow caching of other actually clean files found within archives.
|
// Consider removing this check to allow caching of other actually clean files found within archives.
|
||||||
// It would be a (very) minor optimization.
|
// It would be a (very) minor optimization.
|
||||||
cli_dbgmsg("clean_cache_add: alert found within same topfile, skipping cache\n");
|
cli_dbgmsg("clean_cache_add: alert found within same topfile, skipping cache\n");
|
||||||
return;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Get the hash */
|
||||||
|
ret = fmap_get_hash(ctx->fmap, &sha2_256, CLI_HASH_SHA2_256);
|
||||||
|
if (CL_SUCCESS != ret || NULL == sha2_256) {
|
||||||
|
cli_dbgmsg("clean_cache_add: Failed to get SHA2-256 hash.\n");
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the file size */
|
||||||
|
size = ctx->fmap->len;
|
||||||
|
|
||||||
level = (ctx->fmap && ctx->fmap->dont_cache_flag) ? ctx->recursion_level : 0;
|
level = (ctx->fmap && ctx->fmap->dont_cache_flag) ? ctx->recursion_level : 0;
|
||||||
|
|
||||||
key = getkey(md5, ctx->engine->cache->trees);
|
key = getkey(sha2_256, ctx->engine->cache->trees);
|
||||||
c = &ctx->engine->cache[key];
|
c = &ctx->engine->cache[key];
|
||||||
|
|
||||||
#ifdef CL_THREAD_SAFE
|
#ifdef CL_THREAD_SAFE
|
||||||
if (pthread_mutex_lock(&c->mutex)) {
|
if (pthread_mutex_lock(&c->mutex)) {
|
||||||
cli_errmsg("cli_add: mutex lock fail\n");
|
cli_errmsg("cli_add: mutex lock fail\n");
|
||||||
return;
|
goto done;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
errmsg = cacheset_add(&c->cacheset, md5, size, level);
|
errmsg = cacheset_add(&c->cacheset, sha2_256, size, level);
|
||||||
|
|
||||||
#ifdef CL_THREAD_SAFE
|
#ifdef CL_THREAD_SAFE
|
||||||
pthread_mutex_unlock(&c->mutex);
|
pthread_mutex_unlock(&c->mutex);
|
||||||
|
@ -696,63 +722,110 @@ void clean_cache_add(unsigned char *md5, size_t size, cli_ctx *ctx)
|
||||||
cli_errmsg("%s\n", errmsg);
|
cli_errmsg("%s\n", errmsg);
|
||||||
}
|
}
|
||||||
|
|
||||||
cli_dbgmsg("clean_cache_add: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x (level %u)\n", md5[0], md5[1], md5[2], md5[3], md5[4], md5[5], md5[6], md5[7], md5[8], md5[9], md5[10], md5[11], md5[12], md5[13], md5[14], md5[15], level);
|
cli_dbgmsg("clean_cache_add: "
|
||||||
|
"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x (level %u)\n",
|
||||||
|
sha2_256[0], sha2_256[1], sha2_256[2], sha2_256[3], sha2_256[4], sha2_256[5], sha2_256[6], sha2_256[7],
|
||||||
|
sha2_256[8], sha2_256[9], sha2_256[10], sha2_256[11], sha2_256[12], sha2_256[13], sha2_256[14], sha2_256[15],
|
||||||
|
sha2_256[16], sha2_256[17], sha2_256[18], sha2_256[19], sha2_256[20], sha2_256[21], sha2_256[22], sha2_256[23],
|
||||||
|
sha2_256[24], sha2_256[25], sha2_256[26], sha2_256[27], sha2_256[28], sha2_256[29], sha2_256[30], sha2_256[31],
|
||||||
|
level);
|
||||||
|
|
||||||
|
done:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
void clean_cache_remove(unsigned char *md5, size_t size, const struct cl_engine *engine)
|
void clean_cache_remove(uint8_t *sha2_256, size_t size, const struct cl_engine *engine)
|
||||||
{
|
{
|
||||||
unsigned int key = 0;
|
unsigned int key = 0;
|
||||||
struct CACHE *c;
|
struct CACHE *c;
|
||||||
|
|
||||||
if (!engine || !engine->cache)
|
if (!engine || !engine->cache)
|
||||||
return;
|
goto done;
|
||||||
|
|
||||||
if (engine->engine_options & ENGINE_OPTIONS_DISABLE_CACHE) {
|
if (engine->engine_options & ENGINE_OPTIONS_DISABLE_CACHE) {
|
||||||
cli_dbgmsg("clean_cache_remove: Caching disabled.\n");
|
cli_dbgmsg("clean_cache_remove: Caching disabled.\n");
|
||||||
return;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!md5) {
|
if (!sha2_256) {
|
||||||
cli_dbgmsg("clean_cache_remove: No hash available. Nothing to remove from cache.\n");
|
cli_dbgmsg("clean_cache_remove: No hash available. Nothing to remove from cache.\n");
|
||||||
return;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
key = getkey(md5, engine->cache->trees);
|
key = getkey(sha2_256, engine->cache->trees);
|
||||||
|
|
||||||
c = &engine->cache[key];
|
c = &engine->cache[key];
|
||||||
#ifdef CL_THREAD_SAFE
|
#ifdef CL_THREAD_SAFE
|
||||||
if (pthread_mutex_lock(&c->mutex)) {
|
if (pthread_mutex_lock(&c->mutex)) {
|
||||||
cli_errmsg("cli_add: mutex lock fail\n");
|
cli_errmsg("cli_add: mutex lock fail\n");
|
||||||
return;
|
goto done;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
cacheset_remove(&c->cacheset, md5, size);
|
cacheset_remove(&c->cacheset, sha2_256, size);
|
||||||
|
|
||||||
#ifdef CL_THREAD_SAFE
|
#ifdef CL_THREAD_SAFE
|
||||||
pthread_mutex_unlock(&c->mutex);
|
pthread_mutex_unlock(&c->mutex);
|
||||||
#endif
|
#endif
|
||||||
cli_dbgmsg("clean_cache_remove: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", md5[0], md5[1], md5[2], md5[3], md5[4], md5[5], md5[6], md5[7], md5[8], md5[9], md5[10], md5[11], md5[12], md5[13], md5[14], md5[15]);
|
cli_dbgmsg("clean_cache_remove: "
|
||||||
|
"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n",
|
||||||
|
sha2_256[0], sha2_256[1], sha2_256[2], sha2_256[3], sha2_256[4], sha2_256[5], sha2_256[6], sha2_256[7],
|
||||||
|
sha2_256[8], sha2_256[9], sha2_256[10], sha2_256[11], sha2_256[12], sha2_256[13], sha2_256[14], sha2_256[15],
|
||||||
|
sha2_256[16], sha2_256[17], sha2_256[18], sha2_256[19], sha2_256[20], sha2_256[21], sha2_256[22], sha2_256[23],
|
||||||
|
sha2_256[24], sha2_256[25], sha2_256[26], sha2_256[27], sha2_256[28], sha2_256[29], sha2_256[30], sha2_256[31]);
|
||||||
|
|
||||||
|
done:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
cl_error_t clean_cache_check(unsigned char *md5, size_t size, cli_ctx *ctx)
|
cl_error_t clean_cache_check(cli_ctx *ctx)
|
||||||
{
|
{
|
||||||
int ret;
|
cl_error_t status = CL_VIRUS;
|
||||||
|
uint8_t *sha2_256 = NULL;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
if (!ctx || !ctx->engine || !ctx->engine->cache)
|
if (!ctx || !ctx->engine) {
|
||||||
return CL_VIRUS;
|
cli_errmsg("clean_cache_check: Context or engine is NULL.\n");
|
||||||
|
status = CL_ENULLARG;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!ctx->engine->cache) {
|
||||||
|
if (ctx->engine->engine_options & ENGINE_OPTIONS_DISABLE_CACHE) {
|
||||||
|
cli_dbgmsg("clean_cache_check: Caching is disabled.\n");
|
||||||
|
status = CL_VIRUS;
|
||||||
|
} else {
|
||||||
|
cli_dbgmsg("clean_cache_check: Cache is not initialized.\n");
|
||||||
|
status = CL_ENULLARG;
|
||||||
|
}
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
if (SCAN_COLLECT_METADATA) {
|
if (SCAN_COLLECT_METADATA) {
|
||||||
// Don't cache when using the "collect metadata" feature.
|
// Don't cache when using the "collect metadata" feature.
|
||||||
// We don't cache the JSON, so we can't reproduce it when the cache is positive.
|
// We don't cache the JSON, so we can't reproduce it when the cache is positive.
|
||||||
cli_dbgmsg("clean_cache_check: collect metadata feature enabled, skipping cache\n");
|
cli_dbgmsg("clean_cache_check: collect metadata feature enabled, skipping cache\n");
|
||||||
return CL_VIRUS;
|
status = CL_VIRUS;
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = cache_lookup_hash(md5, size, ctx->engine->cache, ctx->recursion_level);
|
status = fmap_get_hash(ctx->fmap, &sha2_256, CLI_HASH_SHA2_256);
|
||||||
cli_dbgmsg("clean_cache_check: %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x is %s\n", md5[0], md5[1], md5[2], md5[3], md5[4], md5[5], md5[6], md5[7], md5[8], md5[9], md5[10], md5[11], md5[12], md5[13], md5[14], md5[15], (ret == CL_VIRUS) ? "negative" : "positive");
|
if (status != CL_SUCCESS || !sha2_256) {
|
||||||
return ret;
|
cli_dbgmsg("clean_cache_check: Failed to get SHA2-256 hash. Cannot check in cache.\n");
|
||||||
|
status = CL_VIRUS;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
size = ctx->fmap->len;
|
||||||
|
|
||||||
|
status = cache_lookup_hash(sha2_256, size, ctx->engine->cache, ctx->recursion_level);
|
||||||
|
cli_dbgmsg("clean_cache_check: "
|
||||||
|
"%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x is %s\n",
|
||||||
|
sha2_256[0], sha2_256[1], sha2_256[2], sha2_256[3], sha2_256[4], sha2_256[5], sha2_256[6], sha2_256[7],
|
||||||
|
sha2_256[8], sha2_256[9], sha2_256[10], sha2_256[11], sha2_256[12], sha2_256[13], sha2_256[14], sha2_256[15],
|
||||||
|
sha2_256[16], sha2_256[17], sha2_256[18], sha2_256[19], sha2_256[20], sha2_256[21], sha2_256[22], sha2_256[23],
|
||||||
|
sha2_256[24], sha2_256[25], sha2_256[26], sha2_256[27], sha2_256[28], sha2_256[29], sha2_256[30], sha2_256[31],
|
||||||
|
(status == CL_VIRUS) ? "negative" : "positive");
|
||||||
|
|
||||||
|
done:
|
||||||
|
return status;
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,22 +26,20 @@
|
||||||
#include "others.h"
|
#include "others.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Add a hash to the cache of clean files.
|
* @brief Add a hash of the current layer to the cache of clean files.
|
||||||
*
|
*
|
||||||
* @param md5 The file to add.
|
* @param ctx The scanning context.
|
||||||
* @param size The size of the file.
|
|
||||||
* @param ctx The scanning context.
|
|
||||||
*/
|
*/
|
||||||
void clean_cache_add(unsigned char *md5, size_t size, cli_ctx *ctx);
|
void clean_cache_add(cli_ctx *ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Removes a hash from the clean cache
|
* @brief Removes a hash from the clean cache
|
||||||
*
|
*
|
||||||
* @param md5 The file to remove.
|
* @param sha2_256 The file to remove.
|
||||||
* @param size The size of the file.
|
* @param size The size of the file.
|
||||||
* @param ctx The scanning context.
|
* @param ctx The scanning context.
|
||||||
*/
|
*/
|
||||||
void clean_cache_remove(unsigned char *md5, size_t size, const struct cl_engine *engine);
|
void clean_cache_remove(uint8_t *sha2_256, size_t size, const struct cl_engine *engine);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Hashes a file onto the provided buffer and looks it up the clean cache.
|
* @brief Hashes a file onto the provided buffer and looks it up the clean cache.
|
||||||
|
@ -51,7 +49,7 @@ void clean_cache_remove(unsigned char *md5, size_t size, const struct cl_engine
|
||||||
* @return CL_VIRUS if found, CL_CLEAN if not FIXME or a recoverable error.
|
* @return CL_VIRUS if found, CL_CLEAN if not FIXME or a recoverable error.
|
||||||
@return CL_EREAD if unrecoverable.
|
@return CL_EREAD if unrecoverable.
|
||||||
*/
|
*/
|
||||||
cl_error_t clean_cache_check(unsigned char *md5, size_t size, cli_ctx *ctx);
|
cl_error_t clean_cache_check(cli_ctx *ctx);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Allocates the trees for the clean cache.
|
* @brief Allocates the trees for the clean cache.
|
||||||
|
@ -59,7 +57,7 @@ cl_error_t clean_cache_check(unsigned char *md5, size_t size, cli_ctx *ctx);
|
||||||
* @param engine
|
* @param engine
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
int clean_cache_init(struct cl_engine *engine);
|
cl_error_t clean_cache_init(struct cl_engine *engine);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Frees the clean cache
|
* @brief Frees the clean cache
|
||||||
|
|
1558
libclamav/clamav.h
1558
libclamav/clamav.h
File diff suppressed because it is too large
Load diff
|
@ -522,21 +522,21 @@ static int crtmgr_rsa_verify(cli_crt *x509, BIGNUM *sig, cli_crt_hashtype hashty
|
||||||
if (hashtype == CLI_SHA256RSA) {
|
if (hashtype == CLI_SHA256RSA) {
|
||||||
// Check for OID type indicating a length of 9, OID_sha256, and the NULL type/value
|
// Check for OID type indicating a length of 9, OID_sha256, and the NULL type/value
|
||||||
if (0 != memcmp(&d[j], "\x06\x09" OID_sha256 "\x05\x00", 13)) {
|
if (0 != memcmp(&d[j], "\x06\x09" OID_sha256 "\x05\x00", 13)) {
|
||||||
cli_dbgmsg("crtmgr_rsa_verify: invalid AlgorithmIdentifier block for SHA256 hash\n");
|
cli_dbgmsg("crtmgr_rsa_verify: invalid AlgorithmIdentifier block for SHA2-256 hash\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (hashtype == CLI_SHA384RSA) {
|
} else if (hashtype == CLI_SHA384RSA) {
|
||||||
// Check for OID type indicating a length of 9, OID_sha384, and the NULL type/value
|
// Check for OID type indicating a length of 9, OID_sha384, and the NULL type/value
|
||||||
if (0 != memcmp(&d[j], "\x06\x09" OID_sha384 "\x05\x00", 13)) {
|
if (0 != memcmp(&d[j], "\x06\x09" OID_sha384 "\x05\x00", 13)) {
|
||||||
cli_dbgmsg("crtmgr_rsa_verify: invalid AlgorithmIdentifier block for SHA384 hash\n");
|
cli_dbgmsg("crtmgr_rsa_verify: invalid AlgorithmIdentifier block for SHA2-384 hash\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if (hashtype == CLI_SHA512RSA) {
|
} else if (hashtype == CLI_SHA512RSA) {
|
||||||
// Check for OID type indicating a length of 9, OID_sha512, and the NULL type/value
|
// Check for OID type indicating a length of 9, OID_sha512, and the NULL type/value
|
||||||
if (0 != memcmp(&d[j], "\x06\x09" OID_sha512 "\x05\x00", 13)) {
|
if (0 != memcmp(&d[j], "\x06\x09" OID_sha512 "\x05\x00", 13)) {
|
||||||
cli_dbgmsg("crtmgr_rsa_verify: invalid AlgorithmIdentifier block for SHA512 hash\n");
|
cli_dbgmsg("crtmgr_rsa_verify: invalid AlgorithmIdentifier block for SHA2-512 hash\n");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load diff
106
libclamav/cvd.c
106
libclamav/cvd.c
|
@ -41,6 +41,7 @@
|
||||||
#include "zlib.h"
|
#include "zlib.h"
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <openssl/crypto.h>
|
||||||
|
|
||||||
#include "clamav.h"
|
#include "clamav.h"
|
||||||
#include "clamav_rust.h"
|
#include "clamav_rust.h"
|
||||||
|
@ -216,7 +217,7 @@ static int cli_tgzload(cvd_t *cvd, struct cl_engine *engine, unsigned int *signo
|
||||||
dbio->bufpt = NULL;
|
dbio->bufpt = NULL;
|
||||||
dbio->readpt = dbio->buf;
|
dbio->readpt = dbio->buf;
|
||||||
if (!(dbio->hashctx)) {
|
if (!(dbio->hashctx)) {
|
||||||
dbio->hashctx = cl_hash_init("sha256");
|
dbio->hashctx = cl_hash_init("sha2-256");
|
||||||
if (!(dbio->hashctx)) {
|
if (!(dbio->hashctx)) {
|
||||||
cli_tgzload_cleanup(compr, dbio, fdd);
|
cli_tgzload_cleanup(compr, dbio, fdd);
|
||||||
return CL_EMALFDB;
|
return CL_EMALFDB;
|
||||||
|
@ -256,7 +257,7 @@ static int cli_tgzload(cvd_t *cvd, struct cl_engine *engine, unsigned int *signo
|
||||||
return CL_EMALFDB;
|
return CL_EMALFDB;
|
||||||
}
|
}
|
||||||
cl_finish_hash(dbio->hashctx, hash);
|
cl_finish_hash(dbio->hashctx, hash);
|
||||||
dbio->hashctx = cl_hash_init("sha256");
|
dbio->hashctx = cl_hash_init("sha2-256");
|
||||||
if (!(dbio->hashctx)) {
|
if (!(dbio->hashctx)) {
|
||||||
cli_tgzload_cleanup(compr, dbio, fdd);
|
cli_tgzload_cleanup(compr, dbio, fdd);
|
||||||
return CL_EMALFDB;
|
return CL_EMALFDB;
|
||||||
|
@ -394,8 +395,9 @@ struct cl_cvd *cl_cvdhead(const char *file)
|
||||||
if ((pt = strpbrk(head, "\n\r")))
|
if ((pt = strpbrk(head, "\n\r")))
|
||||||
*pt = 0;
|
*pt = 0;
|
||||||
|
|
||||||
for (i = bread - 1; i > 0 && (head[i] == ' ' || head[i] == '\n' || head[i] == '\r'); head[i] = 0, i--)
|
for (i = bread - 1; i > 0 && (head[i] == ' ' || head[i] == '\n' || head[i] == '\r'); head[i] = 0, i--) {
|
||||||
;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
return cl_cvdparse(head);
|
return cl_cvdparse(head);
|
||||||
}
|
}
|
||||||
|
@ -411,10 +413,10 @@ void cl_cvdfree(struct cl_cvd *cvd)
|
||||||
|
|
||||||
cl_error_t cl_cvdverify(const char *file)
|
cl_error_t cl_cvdverify(const char *file)
|
||||||
{
|
{
|
||||||
return cl_cvdverify_ex(file, NULL);
|
return cl_cvdverify_ex(file, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
cl_error_t cl_cvdverify_ex(const char *file, const char *certs_directory)
|
cl_error_t cl_cvdverify_ex(const char *file, const char *certs_directory, uint32_t dboptions)
|
||||||
{
|
{
|
||||||
struct cl_engine *engine = NULL;
|
struct cl_engine *engine = NULL;
|
||||||
cl_error_t ret;
|
cl_error_t ret;
|
||||||
|
@ -455,7 +457,7 @@ cl_error_t cl_cvdverify_ex(const char *file, const char *certs_directory)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = cli_cvdload(engine, NULL, CL_DB_STDOPT | CL_DB_PUA, dbtype, file, verifier, 1);
|
ret = cli_cvdload(engine, NULL, dboptions | CL_DB_STDOPT | CL_DB_PUA, dbtype, file, verifier, true);
|
||||||
|
|
||||||
done:
|
done:
|
||||||
if (NULL != engine) {
|
if (NULL != engine) {
|
||||||
|
@ -471,7 +473,14 @@ done:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
cl_error_t cli_cvdload(struct cl_engine *engine, unsigned int *signo, unsigned int options, cvd_type dbtype, const char *filename, void *sign_verifier, unsigned int chkonly)
|
cl_error_t cli_cvdload(
|
||||||
|
struct cl_engine *engine,
|
||||||
|
unsigned int *signo,
|
||||||
|
uint32_t options,
|
||||||
|
cvd_type dbtype,
|
||||||
|
const char *filename,
|
||||||
|
void *sign_verifier,
|
||||||
|
bool chkonly)
|
||||||
{
|
{
|
||||||
cl_error_t status = CL_ECVD;
|
cl_error_t status = CL_ECVD;
|
||||||
cl_error_t ret;
|
cl_error_t ret;
|
||||||
|
@ -484,11 +493,14 @@ cl_error_t cli_cvdload(struct cl_engine *engine, unsigned int *signo, unsigned i
|
||||||
FFIError *cvd_open_error = NULL;
|
FFIError *cvd_open_error = NULL;
|
||||||
FFIError *cvd_verify_error = NULL;
|
FFIError *cvd_verify_error = NULL;
|
||||||
char *signer_name = NULL;
|
char *signer_name = NULL;
|
||||||
|
bool disable_legacy_dsig = false;
|
||||||
|
|
||||||
dbio.hashctx = NULL;
|
dbio.hashctx = NULL;
|
||||||
|
|
||||||
cli_dbgmsg("in cli_cvdload()\n");
|
cli_dbgmsg("in cli_cvdload()\n");
|
||||||
|
|
||||||
|
disable_legacy_dsig = (options & CL_DB_FIPS_LIMITS) || (engine->engine_options & ENGINE_OPTIONS_FIPS_LIMITS);
|
||||||
|
|
||||||
/* Open the cvd and read the header */
|
/* Open the cvd and read the header */
|
||||||
cvd = cvd_open(filename, &cvd_open_error);
|
cvd = cvd_open(filename, &cvd_open_error);
|
||||||
if (!cvd) {
|
if (!cvd) {
|
||||||
|
@ -501,7 +513,7 @@ cl_error_t cli_cvdload(struct cl_engine *engine, unsigned int *signo, unsigned i
|
||||||
if (!cvd_verify(
|
if (!cvd_verify(
|
||||||
cvd,
|
cvd,
|
||||||
sign_verifier,
|
sign_verifier,
|
||||||
false,
|
disable_legacy_dsig,
|
||||||
&signer_name,
|
&signer_name,
|
||||||
&cvd_verify_error)) {
|
&cvd_verify_error)) {
|
||||||
cli_errmsg("cli_cvdload: Can't verify CVD file %s: %s\n", filename, ffierror_fmt(cvd_verify_error));
|
cli_errmsg("cli_cvdload: Can't verify CVD file %s: %s\n", filename, ffierror_fmt(cvd_verify_error));
|
||||||
|
@ -641,7 +653,53 @@ done:
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
cl_error_t cli_cvdunpack_and_verify(const char *file, const char *dir, bool dont_verify, void *verifier)
|
cl_error_t cli_cvdverify(
|
||||||
|
const char *file,
|
||||||
|
bool disable_legacy_dsig,
|
||||||
|
void *verifier)
|
||||||
|
{
|
||||||
|
cl_error_t status = CL_SUCCESS;
|
||||||
|
cvd_t *cvd = NULL;
|
||||||
|
FFIError *cvd_open_error = NULL;
|
||||||
|
FFIError *cvd_verify_error = NULL;
|
||||||
|
char *signer_name = NULL;
|
||||||
|
|
||||||
|
cvd = cvd_open(file, &cvd_open_error);
|
||||||
|
if (!cvd) {
|
||||||
|
cli_errmsg("Can't open CVD file %s: %s\n", file, ffierror_fmt(cvd_open_error));
|
||||||
|
return CL_EOPEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!cvd_verify(cvd, verifier, disable_legacy_dsig, &signer_name, &cvd_verify_error)) {
|
||||||
|
cli_errmsg("CVD verification failed: %s\n", ffierror_fmt(cvd_verify_error));
|
||||||
|
status = CL_EVERIFY;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
|
||||||
|
if (NULL != signer_name) {
|
||||||
|
ffi_cstring_free(signer_name);
|
||||||
|
}
|
||||||
|
if (NULL != cvd) {
|
||||||
|
cvd_free(cvd);
|
||||||
|
}
|
||||||
|
if (NULL != cvd_open_error) {
|
||||||
|
ffierror_free(cvd_open_error);
|
||||||
|
}
|
||||||
|
if (NULL != cvd_verify_error) {
|
||||||
|
ffierror_free(cvd_verify_error);
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
cl_error_t cli_cvdunpack_and_verify(
|
||||||
|
const char *file,
|
||||||
|
const char *dir,
|
||||||
|
bool dont_verify,
|
||||||
|
bool disable_legacy_dsig,
|
||||||
|
void *verifier)
|
||||||
{
|
{
|
||||||
cl_error_t status = CL_SUCCESS;
|
cl_error_t status = CL_SUCCESS;
|
||||||
cvd_t *cvd = NULL;
|
cvd_t *cvd = NULL;
|
||||||
|
@ -657,7 +715,7 @@ cl_error_t cli_cvdunpack_and_verify(const char *file, const char *dir, bool dont
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!dont_verify) {
|
if (!dont_verify) {
|
||||||
if (!cvd_verify(cvd, verifier, false, &signer_name, &cvd_verify_error)) {
|
if (!cvd_verify(cvd, verifier, disable_legacy_dsig, &signer_name, &cvd_verify_error)) {
|
||||||
cli_errmsg("CVD verification failed: %s\n", ffierror_fmt(cvd_verify_error));
|
cli_errmsg("CVD verification failed: %s\n", ffierror_fmt(cvd_verify_error));
|
||||||
status = CL_EVERIFY;
|
status = CL_EVERIFY;
|
||||||
goto done;
|
goto done;
|
||||||
|
@ -691,7 +749,7 @@ done:
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
cl_error_t cl_cvdunpack_ex(const char *file, const char *dir, bool dont_verify, const char *certs_directory)
|
cl_error_t cl_cvdunpack_ex(const char *file, const char *dir, const char *certs_directory, uint32_t dboptions)
|
||||||
{
|
{
|
||||||
cl_error_t status = CL_SUCCESS;
|
cl_error_t status = CL_SUCCESS;
|
||||||
cvd_t *cvd = NULL;
|
cvd_t *cvd = NULL;
|
||||||
|
@ -707,15 +765,16 @@ cl_error_t cl_cvdunpack_ex(const char *file, const char *dir, bool dont_verify,
|
||||||
return CL_EOPEN;
|
return CL_EOPEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dont_verify) {
|
if (dboptions & CL_DB_UNSIGNED) {
|
||||||
// Just unpack the CVD file.
|
// Just unpack the CVD file and don´t verify the digital signature.
|
||||||
if (!cvd_unpack(cvd, dir, &cvd_unpack_error)) {
|
if (!cvd_unpack(cvd, dir, &cvd_unpack_error)) {
|
||||||
cli_errmsg("CVD unpacking failed: %s\n", ffierror_fmt(cvd_unpack_error));
|
cli_errmsg("CVD unpacking failed: %s\n", ffierror_fmt(cvd_unpack_error));
|
||||||
status = CL_EUNPACK;
|
status = CL_EUNPACK;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Verify the CVD file and hten unpack it.
|
// Verify the CVD file and then unpack it.
|
||||||
|
bool disable_legacy_dsig = false;
|
||||||
|
|
||||||
// The certs directory is optional.
|
// The certs directory is optional.
|
||||||
// If not provided, then we can't validate external signatures and will have to rely
|
// If not provided, then we can't validate external signatures and will have to rely
|
||||||
|
@ -728,7 +787,13 @@ cl_error_t cl_cvdunpack_ex(const char *file, const char *dir, bool dont_verify,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
status = cli_cvdunpack_and_verify(file, dir, dont_verify, verifier);
|
#if OPENSSL_VERSION_MAJOR >= 3
|
||||||
|
disable_legacy_dsig = (dboptions & CL_DB_FIPS_LIMITS) || EVP_default_properties_is_fips_enabled(NULL);
|
||||||
|
#else
|
||||||
|
disable_legacy_dsig = (dboptions & CL_DB_FIPS_LIMITS) || FIPS_mode();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
status = cli_cvdunpack_and_verify(file, dir, false, disable_legacy_dsig, verifier);
|
||||||
if (status != CL_SUCCESS) {
|
if (status != CL_SUCCESS) {
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
@ -766,6 +831,7 @@ cl_error_t cl_cvdunpack(const char *file, const char *dir, bool dont_verify)
|
||||||
FFIError *cvd_verify_error = NULL;
|
FFIError *cvd_verify_error = NULL;
|
||||||
FFIError *cvd_unpack_error = NULL;
|
FFIError *cvd_unpack_error = NULL;
|
||||||
char *signer_name = NULL;
|
char *signer_name = NULL;
|
||||||
|
bool disable_legacy_dsig = false;
|
||||||
|
|
||||||
cvd = cvd_open(file, &cvd_open_error);
|
cvd = cvd_open(file, &cvd_open_error);
|
||||||
if (!cvd) {
|
if (!cvd) {
|
||||||
|
@ -773,8 +839,14 @@ cl_error_t cl_cvdunpack(const char *file, const char *dir, bool dont_verify)
|
||||||
return CL_EOPEN;
|
return CL_EOPEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if OPENSSL_VERSION_MAJOR >= 3
|
||||||
|
disable_legacy_dsig = EVP_default_properties_is_fips_enabled(NULL);
|
||||||
|
#else
|
||||||
|
disable_legacy_dsig = FIPS_mode();
|
||||||
|
#endif
|
||||||
|
|
||||||
if (!dont_verify) {
|
if (!dont_verify) {
|
||||||
if (!cvd_verify(cvd, NULL, false, &signer_name, &cvd_verify_error)) {
|
if (!cvd_verify(cvd, NULL, disable_legacy_dsig, &signer_name, &cvd_verify_error)) {
|
||||||
cli_errmsg("CVD verification failed: %s\n", ffierror_fmt(cvd_verify_error));
|
cli_errmsg("CVD verification failed: %s\n", ffierror_fmt(cvd_verify_error));
|
||||||
status = CL_EVERIFY;
|
status = CL_EVERIFY;
|
||||||
goto done;
|
goto done;
|
||||||
|
|
|
@ -52,7 +52,55 @@ typedef enum cvd_type {
|
||||||
CVD_TYPE_CUD,
|
CVD_TYPE_CUD,
|
||||||
} cvd_type;
|
} cvd_type;
|
||||||
|
|
||||||
cl_error_t cli_cvdload(struct cl_engine *engine, unsigned int *signo, unsigned int options, cvd_type dbtype, const char *filename, void *sign_verifier, unsigned int chkonly);
|
/**
|
||||||
cl_error_t cli_cvdunpack_and_verify(const char *file, const char *dir, bool dont_verify, void *verifier);
|
* @brief Load a CVD, CLD, or CUD signature database archive
|
||||||
|
*
|
||||||
|
* @param engine The ClamAV engine to load the CVD into
|
||||||
|
* @param signo Pointer to the signature number
|
||||||
|
* @param options CL_DB_* options for loading the CVD
|
||||||
|
* @param dbtype Type of the database
|
||||||
|
* @param filename Name of the CVD file
|
||||||
|
* @param sign_verifier Pointer to the signature verifier
|
||||||
|
* @param chkonly Check only mode
|
||||||
|
* @return cl_error_t CL_SUCCESS on success, or an error code on failure
|
||||||
|
*/
|
||||||
|
cl_error_t cli_cvdload(
|
||||||
|
struct cl_engine *engine,
|
||||||
|
unsigned int *signo,
|
||||||
|
uint32_t options,
|
||||||
|
cvd_type dbtype,
|
||||||
|
const char *filename,
|
||||||
|
void *sign_verifier,
|
||||||
|
bool chkonly);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Unpack and verify a CVD, CLD, or CUD signature database archive
|
||||||
|
*
|
||||||
|
* @param file Name of the CVD file
|
||||||
|
* @param dir Directory to unpack the CVD into
|
||||||
|
* @param dont_verify Don't verify signatures
|
||||||
|
* @param disable_legacy_dsig Disable legacy MD5-based digital signature verification
|
||||||
|
* @param verifier Pointer to the signature verifier
|
||||||
|
* @return cl_error_t CL_SUCCESS on success, or an error code on failure
|
||||||
|
*/
|
||||||
|
cl_error_t cli_cvdunpack_and_verify(
|
||||||
|
const char *file,
|
||||||
|
const char *dir,
|
||||||
|
bool dont_verify,
|
||||||
|
bool disable_legacy_dsig,
|
||||||
|
void *verifier);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Verify a CVD, CLD, or CUD signature database archive
|
||||||
|
*
|
||||||
|
* @param file Name of the CVD file
|
||||||
|
* @param disable_legacy_dsig Disable legacy MD5-based digital signature verification
|
||||||
|
* @param verifier Pointer to the signature verifier
|
||||||
|
* @return cl_error_t CL_SUCCESS on success, or an error code on failure
|
||||||
|
*/
|
||||||
|
cl_error_t cli_cvdverify(
|
||||||
|
const char *file,
|
||||||
|
bool disable_legacy_dsig,
|
||||||
|
void *verifier);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -146,7 +146,7 @@ int cli_scandmg(cli_ctx *ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create temp folder for contents */
|
/* Create temp folder for contents */
|
||||||
if (!(dirname = cli_gentemp_with_prefix(ctx->sub_tmpdir, "dmg-tmp"))) {
|
if (!(dirname = cli_gentemp_with_prefix(ctx->this_layer_tmpdir, "dmg-tmp"))) {
|
||||||
return CL_ETMPDIR;
|
return CL_ETMPDIR;
|
||||||
}
|
}
|
||||||
if (mkdir(dirname, 0700)) {
|
if (mkdir(dirname, 0700)) {
|
||||||
|
|
|
@ -299,20 +299,20 @@ cl_error_t cli_versig(const char *md5, const char *dsig)
|
||||||
if (!BN_dec2bn(&n, CLI_NSTR))
|
if (!BN_dec2bn(&n, CLI_NSTR))
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
if (strlen(md5) != 32 || !isalnum(md5[0])) {
|
if (strlen(md5) != MD5_HASH_SIZE * 2 || !isalnum(md5[0])) {
|
||||||
/* someone is trying to fool us with empty/malformed MD5 ? */
|
/* someone is trying to fool us with empty/malformed MD5 ? */
|
||||||
cli_errmsg("SECURITY WARNING: MD5 basic test failure.\n");
|
cli_errmsg("SECURITY WARNING: MD5 basic test failure.\n");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(pt = (char *)cli_decodesig(dsig, 16, e, n)))
|
if (!(pt = (char *)cli_decodesig(dsig, MD5_HASH_SIZE, e, n)))
|
||||||
goto done;
|
goto done;
|
||||||
|
|
||||||
pt2 = cli_str2hex(pt, 16);
|
pt2 = cli_str2hex(pt, MD5_HASH_SIZE);
|
||||||
|
|
||||||
cli_dbgmsg("cli_versig: Decoded signature: %s\n", pt2);
|
cli_dbgmsg("cli_versig: Decoded signature: %s\n", pt2);
|
||||||
|
|
||||||
if (strncmp(md5, pt2, 32)) {
|
if (strncmp(md5, pt2, MD5_HASH_SIZE * 2)) {
|
||||||
cli_dbgmsg("cli_versig: Signature doesn't match.\n");
|
cli_dbgmsg("cli_versig: Signature doesn't match.\n");
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
@ -328,19 +328,18 @@ done:
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define HASH_LEN 32
|
|
||||||
#define SALT_LEN 32
|
#define SALT_LEN 32
|
||||||
#define PAD_LEN (2048 / 8)
|
#define PAD_LEN (2048 / 8)
|
||||||
#define BLK_LEN (PAD_LEN - HASH_LEN - 1)
|
#define BLK_LEN (PAD_LEN - SHA256_HASH_SIZE - 1)
|
||||||
int cli_versig2(const unsigned char *sha256, const char *dsig_str, const char *n_str, const char *e_str)
|
cl_error_t cli_versig2(const uint8_t *sha2_256, const char *dsig_str, const char *n_str, const char *e_str)
|
||||||
{
|
{
|
||||||
unsigned char *decoded = NULL;
|
uint8_t *decoded = NULL;
|
||||||
unsigned char digest1[HASH_LEN], digest2[HASH_LEN], digest3[HASH_LEN], *salt;
|
uint8_t digest1[SHA256_HASH_SIZE], digest2[SHA256_HASH_SIZE], digest3[SHA256_HASH_SIZE], *salt;
|
||||||
unsigned char mask[BLK_LEN], data[BLK_LEN], final[8 + 2 * HASH_LEN], c[4];
|
uint8_t mask[BLK_LEN], data[BLK_LEN], final[8 + 2 * SHA256_HASH_SIZE], c[4];
|
||||||
unsigned int i, rounds;
|
unsigned int i, rounds;
|
||||||
void *ctx;
|
void *ctx;
|
||||||
BIGNUM *n, *e;
|
BIGNUM *n, *e;
|
||||||
int ret;
|
cl_error_t ret;
|
||||||
|
|
||||||
n = BN_new();
|
n = BN_new();
|
||||||
e = BN_new();
|
e = BN_new();
|
||||||
|
@ -374,27 +373,27 @@ int cli_versig2(const unsigned char *sha256, const char *dsig_str, const char *n
|
||||||
e = NULL;
|
e = NULL;
|
||||||
|
|
||||||
memcpy(mask, decoded, BLK_LEN);
|
memcpy(mask, decoded, BLK_LEN);
|
||||||
memcpy(digest2, &decoded[BLK_LEN], HASH_LEN);
|
memcpy(digest2, &decoded[BLK_LEN], SHA256_HASH_SIZE);
|
||||||
free(decoded);
|
free(decoded);
|
||||||
decoded = NULL;
|
decoded = NULL;
|
||||||
|
|
||||||
c[0] = c[1] = 0;
|
c[0] = c[1] = 0;
|
||||||
rounds = (BLK_LEN + HASH_LEN - 1) / HASH_LEN;
|
rounds = (BLK_LEN + SHA256_HASH_SIZE - 1) / SHA256_HASH_SIZE;
|
||||||
for (i = 0; i < rounds; i++) {
|
for (i = 0; i < rounds; i++) {
|
||||||
c[2] = (unsigned char)(i / 256);
|
c[2] = (unsigned char)(i / 256);
|
||||||
c[3] = (unsigned char)i;
|
c[3] = (unsigned char)i;
|
||||||
|
|
||||||
ctx = cl_hash_init("sha256");
|
ctx = cl_hash_init("sha2-256");
|
||||||
if (!(ctx))
|
if (!(ctx))
|
||||||
return CL_EMEM;
|
return CL_EMEM;
|
||||||
|
|
||||||
cl_update_hash(ctx, digest2, HASH_LEN);
|
cl_update_hash(ctx, digest2, SHA256_HASH_SIZE);
|
||||||
cl_update_hash(ctx, c, 4);
|
cl_update_hash(ctx, c, 4);
|
||||||
cl_finish_hash(ctx, digest3);
|
cl_finish_hash(ctx, digest3);
|
||||||
if (i + 1 == rounds)
|
if (i + 1 == rounds)
|
||||||
memcpy(&data[i * 32], digest3, BLK_LEN - i * HASH_LEN);
|
memcpy(&data[i * 32], digest3, BLK_LEN - i * SHA256_HASH_SIZE);
|
||||||
else
|
else
|
||||||
memcpy(&data[i * 32], digest3, HASH_LEN);
|
memcpy(&data[i * 32], digest3, SHA256_HASH_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < BLK_LEN; i++)
|
for (i = 0; i < BLK_LEN; i++)
|
||||||
|
@ -409,17 +408,17 @@ int cli_versig2(const unsigned char *sha256, const char *dsig_str, const char *n
|
||||||
return CL_EVERIFY;
|
return CL_EVERIFY;
|
||||||
|
|
||||||
memset(final, 0, 8);
|
memset(final, 0, 8);
|
||||||
memcpy(&final[8], sha256, HASH_LEN);
|
memcpy(&final[8], sha2_256, SHA256_HASH_SIZE);
|
||||||
memcpy(&final[8 + HASH_LEN], salt, SALT_LEN);
|
memcpy(&final[8 + SHA256_HASH_SIZE], salt, SALT_LEN);
|
||||||
|
|
||||||
ctx = cl_hash_init("sha256");
|
ctx = cl_hash_init("sha2-256");
|
||||||
if (!(ctx))
|
if (!(ctx))
|
||||||
return CL_EMEM;
|
return CL_EMEM;
|
||||||
|
|
||||||
cl_update_hash(ctx, final, sizeof(final));
|
cl_update_hash(ctx, final, sizeof(final));
|
||||||
cl_finish_hash(ctx, digest1);
|
cl_finish_hash(ctx, digest1);
|
||||||
|
|
||||||
return memcmp(digest1, digest2, HASH_LEN) ? CL_EVERIFY : CL_SUCCESS;
|
return memcmp(digest1, digest2, SHA256_HASH_SIZE) ? CL_EVERIFY : CL_SUCCESS;
|
||||||
|
|
||||||
done:
|
done:
|
||||||
free(decoded);
|
free(decoded);
|
||||||
|
|
|
@ -30,7 +30,7 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
cl_error_t cli_versig(const char *md5, const char *dsig);
|
cl_error_t cli_versig(const char *md5, const char *dsig);
|
||||||
int cli_versig2(const unsigned char *sha256, const char *dsig_str, const char *n_str, const char *e_str);
|
cl_error_t cli_versig2(const unsigned char *sha2_256, const char *dsig_str, const char *n_str, const char *e_str);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Connect to a signing server, send the data to be signed, and return the digital signature.
|
* @brief Connect to a signing server, send the data to be signed, and return the digital signature.
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
* | Archive Comment Header | 0~N |
|
* | Archive Comment Header | 0~N |
|
||||||
* |-----------------------------------------------------|------|
|
* |-----------------------------------------------------|------|
|
||||||
*
|
*
|
||||||
* Authors: Micah Snyder
|
* Authors: Valerie Snyder
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
|
|
@ -9,7 +9,7 @@
|
||||||
* ESTsoft's "unEGG" module was not used in the creation of this capability
|
* ESTsoft's "unEGG" module was not used in the creation of this capability
|
||||||
* in order to avoid to licensing restrictions on the ESTsoft "unEGG" module.
|
* in order to avoid to licensing restrictions on the ESTsoft "unEGG" module.
|
||||||
*
|
*
|
||||||
* Authors: Micah Snyder
|
* Authors: Valerie Snyder
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
|
|
@ -526,9 +526,11 @@ static void iconv_cache_init(struct iconv_cache* cache)
|
||||||
static void iconv_cache_destroy(struct iconv_cache* cache)
|
static void iconv_cache_destroy(struct iconv_cache* cache)
|
||||||
{
|
{
|
||||||
size_t i;
|
size_t i;
|
||||||
cli_dbgmsg(MODULE_NAME "Destroying iconv pool:%p\n", (void*)cache);
|
// Don't use cli_dbgmsg() in destroy, because this happens *after* main() exits and we've already closed the log file handle.
|
||||||
|
//printf(MODULE_NAME "Destroying iconv pool:%p\n", (void*)cache);
|
||||||
for (i = 0; i < cache->last; i++) {
|
for (i = 0; i < cache->last; i++) {
|
||||||
cli_dbgmsg(MODULE_NAME "closing iconv:%p\n", cache->tab[i]);
|
// Don't log on destroy, because this happens *after* main() exits and we've already closed the log file handle.
|
||||||
|
//printf(MODULE_NAME "closing iconv:%p\n", cache->tab[i]);
|
||||||
iconv_close(cache->tab[i]);
|
iconv_close(cache->tab[i]);
|
||||||
}
|
}
|
||||||
cli_hashtab_clear(&cache->hashtab);
|
cli_hashtab_clear(&cache->hashtab);
|
||||||
|
|
|
@ -147,6 +147,55 @@ static const struct ftmap_s {
|
||||||
};
|
};
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
|
cli_file_t cli_ftcode_human_friendly(const char *name)
|
||||||
|
{
|
||||||
|
cli_file_t code = CL_TYPE_ERROR;
|
||||||
|
|
||||||
|
unsigned int i;
|
||||||
|
char *reconstructed_name = NULL;
|
||||||
|
const char *ftname;
|
||||||
|
|
||||||
|
if (NULL == name) {
|
||||||
|
cli_dbgmsg("cli_ftcode_human_friendly: NULL name\n");
|
||||||
|
code = CL_TYPE_ERROR;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (0 == strncmp(name, "CL_TYPE_", strlen("CL_TYPE_"))) {
|
||||||
|
/* If the name starts with "CL_TYPE_", we can use it directly. */
|
||||||
|
ftname = name;
|
||||||
|
} else {
|
||||||
|
/* If the name does not start with "CL_TYPE_", let's prefix "CL_TYPE_" and convert it to uppercase. */
|
||||||
|
size_t len = strlen(name) + strlen("CL_TYPE_") + 1;
|
||||||
|
|
||||||
|
reconstructed_name = malloc(len);
|
||||||
|
if (NULL == reconstructed_name) {
|
||||||
|
cli_dbgmsg("cli_ftcode_human_friendly: Failed to allocate memory for reconstructed name\n");
|
||||||
|
code = CL_TYPE_ERROR;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
snprintf(reconstructed_name, len, "CL_TYPE_%s", name);
|
||||||
|
|
||||||
|
/* Convert to uppercase */
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
reconstructed_name[i] = toupper((unsigned char)reconstructed_name[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
ftname = reconstructed_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
code = cli_ftcode(ftname);
|
||||||
|
if (CL_TYPE_ERROR == code) {
|
||||||
|
cli_dbgmsg("cli_ftcode_human_friendly: Unknown file type '%s'\n", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
if (NULL != reconstructed_name) {
|
||||||
|
free(reconstructed_name);
|
||||||
|
}
|
||||||
|
return code;
|
||||||
|
}
|
||||||
|
|
||||||
cli_file_t cli_ftcode(const char *name)
|
cli_file_t cli_ftcode(const char *name)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
@ -278,7 +327,7 @@ const struct ooxml_ftcodes {
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
cli_file_t cli_determine_fmap_type(fmap_t *map, const struct cl_engine *engine, cli_file_t basetype)
|
cli_file_t cli_determine_fmap_type(cli_ctx_t ctx_t, cli_file_t basetype)
|
||||||
{
|
{
|
||||||
unsigned char buffer[MAGIC_BUFFER_SIZE];
|
unsigned char buffer[MAGIC_BUFFER_SIZE];
|
||||||
const unsigned char *buff;
|
const unsigned char *buff;
|
||||||
|
@ -288,23 +337,24 @@ cli_file_t cli_determine_fmap_type(fmap_t *map, const struct cl_engine *engine,
|
||||||
cli_file_t ret = CL_TYPE_BINARY_DATA;
|
cli_file_t ret = CL_TYPE_BINARY_DATA;
|
||||||
struct cli_matcher *root;
|
struct cli_matcher *root;
|
||||||
struct cli_ac_data mdata;
|
struct cli_ac_data mdata;
|
||||||
|
cli_ctx *ctx = (cli_ctx *)ctx_t;
|
||||||
|
|
||||||
if (!engine) {
|
if (!ctx || !ctx->engine || !ctx->fmap) {
|
||||||
cli_errmsg("cli_determine_fmap_type: engine == NULL\n");
|
cli_errmsg("cli_determine_fmap_type: engine == NULL\n");
|
||||||
return CL_TYPE_ERROR;
|
return CL_TYPE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (basetype == CL_TYPE_PART_ANY) {
|
if (basetype == CL_TYPE_PART_ANY) {
|
||||||
bread = MIN(map->len, CL_PART_MBUFF_SIZE);
|
bread = MIN(ctx->fmap->len, CL_PART_MBUFF_SIZE);
|
||||||
} else {
|
} else {
|
||||||
bread = MIN(map->len, CL_FILE_MBUFF_SIZE);
|
bread = MIN(ctx->fmap->len, CL_FILE_MBUFF_SIZE);
|
||||||
}
|
}
|
||||||
if (bread > MAGIC_BUFFER_SIZE) {
|
if (bread > MAGIC_BUFFER_SIZE) {
|
||||||
/* Save anyone who tampered with the header */
|
/* Save anyone who tampered with the header */
|
||||||
bread = MAGIC_BUFFER_SIZE;
|
bread = MAGIC_BUFFER_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
buff = fmap_need_off_once(map, 0, bread);
|
buff = fmap_need_off_once(ctx->fmap, 0, bread);
|
||||||
if (buff) {
|
if (buff) {
|
||||||
if (CL_SUCCESS != cli_memcpy(buffer, buff, bread)) {
|
if (CL_SUCCESS != cli_memcpy(buffer, buff, bread)) {
|
||||||
cli_errmsg("cli_determine_fmap_type: fileread error!\n");
|
cli_errmsg("cli_determine_fmap_type: fileread error!\n");
|
||||||
|
@ -315,9 +365,9 @@ cli_file_t cli_determine_fmap_type(fmap_t *map, const struct cl_engine *engine,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (basetype == CL_TYPE_PART_ANY) { /* typing a partition */
|
if (basetype == CL_TYPE_PART_ANY) { /* typing a partition */
|
||||||
ret = cli_compare_ftm_partition(buff, bread, engine);
|
ret = cli_compare_ftm_partition(buff, bread, ctx->engine);
|
||||||
} else { /* typing a file */
|
} else { /* typing a file */
|
||||||
ret = cli_compare_ftm_file(buff, bread, engine);
|
ret = cli_compare_ftm_file(buff, bread, ctx->engine);
|
||||||
|
|
||||||
if (ret == CL_TYPE_BINARY_DATA) {
|
if (ret == CL_TYPE_BINARY_DATA) {
|
||||||
switch (is_tar(buff, bread)) {
|
switch (is_tar(buff, bread)) {
|
||||||
|
@ -361,7 +411,7 @@ cli_file_t cli_determine_fmap_type(fmap_t *map, const struct cl_engine *engine,
|
||||||
/* if likely, check full archive */
|
/* if likely, check full archive */
|
||||||
if (likely_ooxml) {
|
if (likely_ooxml) {
|
||||||
cli_dbgmsg("Likely OOXML, checking additional zip headers\n");
|
cli_dbgmsg("Likely OOXML, checking additional zip headers\n");
|
||||||
if ((ret2 = cli_ooxml_filetype(NULL, map)) != CL_TYPE_ANY) {
|
if ((ret2 = cli_ooxml_filetype(ctx)) != CL_TYPE_ANY) {
|
||||||
/* either an error or retyping has occurred, return error or just CL_TYPE_ZIP? */
|
/* either an error or retyping has occurred, return error or just CL_TYPE_ZIP? */
|
||||||
OOXML_FTIDENTIFIED(ret2);
|
OOXML_FTIDENTIFIED(ret2);
|
||||||
/* falls-through to additional filetyping */
|
/* falls-through to additional filetyping */
|
||||||
|
@ -375,10 +425,10 @@ cli_file_t cli_determine_fmap_type(fmap_t *map, const struct cl_engine *engine,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (znamep == NULL) {
|
if (znamep == NULL) {
|
||||||
if (map->len - zoff > SIZEOF_LOCAL_HEADER) {
|
if (ctx->fmap->len - zoff > SIZEOF_LOCAL_HEADER) {
|
||||||
zoff -= SIZEOF_LOCAL_HEADER + OOXML_DETECT_MAXLEN + 1; /* remap for SIZEOF_LOCAL_HEADER+filelen for header overlap map boundary */
|
zoff -= SIZEOF_LOCAL_HEADER + OOXML_DETECT_MAXLEN + 1; /* remap for SIZEOF_LOCAL_HEADER+filelen for header overlap map boundary */
|
||||||
zread = MIN(MAGIC_BUFFER_SIZE, map->len - zoff);
|
zread = MIN(MAGIC_BUFFER_SIZE, ctx->fmap->len - zoff);
|
||||||
zbuff = fmap_need_off_once(map, zoff, zread);
|
zbuff = fmap_need_off_once(ctx->fmap, zoff, zread);
|
||||||
if (zbuff == NULL) {
|
if (zbuff == NULL) {
|
||||||
cli_dbgmsg("cli_determine_fmap_type: error mapping data for OOXML check\n");
|
cli_dbgmsg("cli_determine_fmap_type: error mapping data for OOXML check\n");
|
||||||
return CL_TYPE_ERROR;
|
return CL_TYPE_ERROR;
|
||||||
|
@ -393,7 +443,7 @@ cli_file_t cli_determine_fmap_type(fmap_t *map, const struct cl_engine *engine,
|
||||||
}
|
}
|
||||||
} else if (ret == CL_TYPE_MBR) {
|
} else if (ret == CL_TYPE_MBR) {
|
||||||
/* given filetype sig type 0 */
|
/* given filetype sig type 0 */
|
||||||
int iret = cli_mbr_check(buff, bread, map->len);
|
int iret = cli_mbr_check(buff, bread, ctx->fmap->len);
|
||||||
if (iret == CL_TYPE_GPT) {
|
if (iret == CL_TYPE_GPT) {
|
||||||
cli_dbgmsg("Recognized GUID Partition Table file\n");
|
cli_dbgmsg("Recognized GUID Partition Table file\n");
|
||||||
return CL_TYPE_GPT;
|
return CL_TYPE_GPT;
|
||||||
|
@ -411,14 +461,14 @@ cli_file_t cli_determine_fmap_type(fmap_t *map, const struct cl_engine *engine,
|
||||||
/* HTML files may contain special characters and could be
|
/* HTML files may contain special characters and could be
|
||||||
* misidentified as BINARY_DATA by cli_compare_ftm_file()
|
* misidentified as BINARY_DATA by cli_compare_ftm_file()
|
||||||
*/
|
*/
|
||||||
root = engine->root[0];
|
root = ctx->engine->root[0];
|
||||||
if (!root)
|
if (!root)
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if (cli_ac_initdata(&mdata, root->ac_partsigs, root->ac_lsigs, root->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN))
|
if (cli_ac_initdata(&mdata, root->ac_partsigs, root->ac_lsigs, root->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN))
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
scan_ret = (cli_file_t)cli_ac_scanbuff(buff, bread, NULL, NULL, NULL, engine->root[0], &mdata, 0, ret, NULL, AC_SCAN_FT, NULL);
|
scan_ret = (cli_file_t)cli_ac_scanbuff(buff, bread, NULL, NULL, NULL, ctx->engine->root[0], &mdata, 0, ret, NULL, AC_SCAN_FT, NULL);
|
||||||
|
|
||||||
cli_ac_freedata(&mdata);
|
cli_ac_freedata(&mdata);
|
||||||
|
|
||||||
|
@ -437,14 +487,14 @@ cli_file_t cli_determine_fmap_type(fmap_t *map, const struct cl_engine *engine,
|
||||||
|
|
||||||
decoded = (unsigned char *)cli_utf16toascii((char *)buff, bread);
|
decoded = (unsigned char *)cli_utf16toascii((char *)buff, bread);
|
||||||
if (decoded) {
|
if (decoded) {
|
||||||
scan_ret = (cli_file_t)cli_ac_scanbuff(decoded, bread / 2, NULL, NULL, NULL, engine->root[0], &mdata, 0, CL_TYPE_TEXT_ASCII, NULL, AC_SCAN_FT, NULL);
|
scan_ret = (cli_file_t)cli_ac_scanbuff(decoded, bread / 2, NULL, NULL, NULL, ctx->engine->root[0], &mdata, 0, CL_TYPE_TEXT_ASCII, NULL, AC_SCAN_FT, NULL);
|
||||||
free(decoded);
|
free(decoded);
|
||||||
if (scan_ret == CL_TYPE_HTML)
|
if (scan_ret == CL_TYPE_HTML)
|
||||||
ret = CL_TYPE_HTML_UTF16;
|
ret = CL_TYPE_HTML_UTF16;
|
||||||
}
|
}
|
||||||
cli_ac_freedata(&mdata);
|
cli_ac_freedata(&mdata);
|
||||||
|
|
||||||
if ((((struct cli_dconf *)engine->dconf)->phishing & PHISHING_CONF_ENTCONV) && ret != CL_TYPE_HTML_UTF16) {
|
if ((((struct cli_dconf *)ctx->engine->dconf)->phishing & PHISHING_CONF_ENTCONV) && ret != CL_TYPE_HTML_UTF16) {
|
||||||
const char *encoding;
|
const char *encoding;
|
||||||
|
|
||||||
/* check if we can autodetect this encoding.
|
/* check if we can autodetect this encoding.
|
||||||
|
@ -472,7 +522,7 @@ cli_file_t cli_determine_fmap_type(fmap_t *map, const struct cl_engine *engine,
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
if (out_area.length > 0) {
|
if (out_area.length > 0) {
|
||||||
scan_ret = (cli_file_t)cli_ac_scanbuff(decodedbuff, out_area.length, NULL, NULL, NULL, engine->root[0], &mdata, 0, 0, NULL, AC_SCAN_FT, NULL); /* FIXME: can we use CL_TYPE_TEXT_ASCII instead of 0? */
|
scan_ret = (cli_file_t)cli_ac_scanbuff(decodedbuff, out_area.length, NULL, NULL, NULL, ctx->engine->root[0], &mdata, 0, 0, NULL, AC_SCAN_FT, NULL); /* FIXME: can we use CL_TYPE_TEXT_ASCII instead of 0? */
|
||||||
if (scan_ret == CL_TYPE_HTML) {
|
if (scan_ret == CL_TYPE_HTML) {
|
||||||
cli_dbgmsg("cli_determine_fmap_type: detected HTML signature in Unicode file\n");
|
cli_dbgmsg("cli_determine_fmap_type: detected HTML signature in Unicode file\n");
|
||||||
/* htmlnorm is able to handle any unicode now, since it skips null chars */
|
/* htmlnorm is able to handle any unicode now, since it skips null chars */
|
||||||
|
|
|
@ -25,7 +25,7 @@
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
|
||||||
#include "clamav.h"
|
#include "clamav.h"
|
||||||
#include "fmap.h"
|
#include "other_types.h"
|
||||||
|
|
||||||
#define CL_FILE_MBUFF_SIZE 1024
|
#define CL_FILE_MBUFF_SIZE 1024
|
||||||
#define CL_PART_MBUFF_SIZE 1028
|
#define CL_PART_MBUFF_SIZE 1028
|
||||||
|
@ -148,12 +148,34 @@ struct cli_matched_type {
|
||||||
unsigned short cnt;
|
unsigned short cnt;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Convert a file type name to a file type code.
|
||||||
|
*
|
||||||
|
* @param name The name of the file type. E.g. "CL_TYPE_PE", "CL_TYPE_ELF", etc.
|
||||||
|
* @return cli_file_t
|
||||||
|
*/
|
||||||
cli_file_t cli_ftcode(const char *name);
|
cli_file_t cli_ftcode(const char *name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Convert a human-friendly file type name to a file type code.
|
||||||
|
*
|
||||||
|
* @param name The human-friendly name of the file type. E.g. "pe", "ZIP", "CL_TYPE_ELF", etc.
|
||||||
|
* @return cli_file_t
|
||||||
|
*/
|
||||||
|
cli_file_t cli_ftcode_human_friendly(const char *name);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Convert a file type code to a file type name.
|
||||||
|
*
|
||||||
|
* @param code The file type code. E.g. CL_TYPE_PE, CL_TYPE_ELF, etc.
|
||||||
|
* @return const char* A ame of the file type. E.g. "CL_TYPE_PE", "CL_TYPE_ELF", etc.
|
||||||
|
*/
|
||||||
const char *cli_ftname(cli_file_t code);
|
const char *cli_ftname(cli_file_t code);
|
||||||
|
|
||||||
void cli_ftfree(const struct cl_engine *engine);
|
void cli_ftfree(const struct cl_engine *engine);
|
||||||
cli_file_t cli_compare_ftm_file(const unsigned char *buf, size_t buflen, const struct cl_engine *engine);
|
cli_file_t cli_compare_ftm_file(const unsigned char *buf, size_t buflen, const struct cl_engine *engine);
|
||||||
cli_file_t cli_compare_ftm_partition(const unsigned char *buf, size_t buflen, const struct cl_engine *engine);
|
cli_file_t cli_compare_ftm_partition(const unsigned char *buf, size_t buflen, const struct cl_engine *engine);
|
||||||
cli_file_t cli_determine_fmap_type(fmap_t *map, const struct cl_engine *engine, cli_file_t basetype);
|
cli_file_t cli_determine_fmap_type(cli_ctx_t ctx, cli_file_t basetype);
|
||||||
int cli_addtypesigs(struct cl_engine *engine);
|
int cli_addtypesigs(struct cl_engine *engine);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -324,5 +324,7 @@ static const char *ftypes_int[] = {
|
||||||
"1:0:08??12??6f6e6e782d636166666532:ONNX AI Model File:CL_TYPE_ANY:CL_TYPE_AI_MODEL:220",
|
"1:0:08??12??6f6e6e782d636166666532:ONNX AI Model File:CL_TYPE_ANY:CL_TYPE_AI_MODEL:220",
|
||||||
// tflite model detection
|
// tflite model detection
|
||||||
"0:4:54464c33:TensorFlow Lite Model File:CL_TYPE_ANY:CL_TYPE_AI_MODEL:220",
|
"0:4:54464c33:TensorFlow Lite Model File:CL_TYPE_ANY:CL_TYPE_AI_MODEL:220",
|
||||||
|
"0:0:504b0708504b0304:ZIP (First segment split/spanned):CL_TYPE_ANY:CL_TYPE_ZIP",
|
||||||
|
"0:0:504b0303504b0304:ZIP (Single-segment split/spanned):CL_TYPE_ANY:CL_TYPE_ZIP",
|
||||||
NULL};
|
NULL};
|
||||||
#endif
|
#endif
|
||||||
|
|
650
libclamav/fmap.c
650
libclamav/fmap.c
|
@ -108,7 +108,7 @@ static off_t pread_cb(void *handle, void *buf, size_t count, off_t offset)
|
||||||
return pread((int)(ssize_t)handle, buf, count, offset);
|
return pread((int)(ssize_t)handle, buf, count, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
fmap_t *fmap_check_empty(int fd, off_t offset, size_t len, int *empty, const char *name)
|
fmap_t *fmap_check_empty(int fd, off_t offset, size_t len, int *empty, const char *name, const char *path)
|
||||||
{
|
{
|
||||||
STATBUF st;
|
STATBUF st;
|
||||||
fmap_t *m = NULL;
|
fmap_t *m = NULL;
|
||||||
|
@ -137,7 +137,15 @@ fmap_t *fmap_check_empty(int fd, off_t offset, size_t len, int *empty, const cha
|
||||||
if (NULL != name) {
|
if (NULL != name) {
|
||||||
m->name = cli_safer_strdup(name);
|
m->name = cli_safer_strdup(name);
|
||||||
if (NULL == m->name) {
|
if (NULL == m->name) {
|
||||||
funmap(m);
|
fmap_free(m);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NULL != path) {
|
||||||
|
m->path = cli_safer_strdup(path);
|
||||||
|
if (NULL == m->path) {
|
||||||
|
fmap_free(m);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -158,11 +166,14 @@ static void unmap_win32(fmap_t *m)
|
||||||
if (NULL != m->name) {
|
if (NULL != m->name) {
|
||||||
free(m->name);
|
free(m->name);
|
||||||
}
|
}
|
||||||
|
if (NULL != m->path) {
|
||||||
|
free(m->path);
|
||||||
|
}
|
||||||
free((void *)m);
|
free((void *)m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fmap_t *fmap_check_empty(int fd, off_t offset, size_t len, int *empty, const char *name)
|
fmap_t *fmap_check_empty(int fd, off_t offset, size_t len, int *empty, const char *name, const char *path)
|
||||||
{ /* WIN32 */
|
{ /* WIN32 */
|
||||||
uint64_t pages, mapsz;
|
uint64_t pages, mapsz;
|
||||||
int pgsz = cli_getpagesize();
|
int pgsz = cli_getpagesize();
|
||||||
|
@ -214,7 +225,7 @@ fmap_t *fmap_check_empty(int fd, off_t offset, size_t len, int *empty, const cha
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
m->handle = (void *)(size_t)fd;
|
m->handle = (void *)(size_t)fd;
|
||||||
m->handle_is_fd = true; /* This is probably(?) needed so `fmap_fd()` can return the file descriptor. */
|
m->handle_is_fd = true;
|
||||||
m->windows_file_handle = (void *)windows_file_handle;
|
m->windows_file_handle = (void *)windows_file_handle;
|
||||||
m->windows_map_handle = (void *)windows_map_handle;
|
m->windows_map_handle = (void *)windows_map_handle;
|
||||||
m->unmap = unmap_win32;
|
m->unmap = unmap_win32;
|
||||||
|
@ -222,7 +233,15 @@ fmap_t *fmap_check_empty(int fd, off_t offset, size_t len, int *empty, const cha
|
||||||
if (NULL != name) {
|
if (NULL != name) {
|
||||||
m->name = cli_safer_strdup(name);
|
m->name = cli_safer_strdup(name);
|
||||||
if (NULL == m->name) {
|
if (NULL == m->name) {
|
||||||
funmap(m);
|
fmap_free(m);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NULL != path) {
|
||||||
|
m->path = cli_safer_strdup(path);
|
||||||
|
if (NULL == m->path) {
|
||||||
|
fmap_free(m);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -287,9 +306,8 @@ fmap_t *fmap_duplicate(cl_fmap_t *map, size_t offset, size_t length, const char
|
||||||
/* This also means the hash will be different.
|
/* This also means the hash will be different.
|
||||||
* Clear the have_<hash> flags.
|
* Clear the have_<hash> flags.
|
||||||
* It will be calculated when next it is needed. */
|
* It will be calculated when next it is needed. */
|
||||||
duplicate_map->have_md5 = false;
|
memset(duplicate_map->will_need_hash, 0, sizeof(duplicate_map->will_need_hash));
|
||||||
duplicate_map->have_sha1 = false;
|
memset(duplicate_map->have_hash, 0, sizeof(duplicate_map->have_hash));
|
||||||
duplicate_map->have_sha256 = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (NULL != name) {
|
if (NULL != name) {
|
||||||
|
@ -302,6 +320,17 @@ fmap_t *fmap_duplicate(cl_fmap_t *map, size_t offset, size_t length, const char
|
||||||
duplicate_map->name = NULL;
|
duplicate_map->name = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Duplicate the path if it exists */
|
||||||
|
if (NULL != map->path) {
|
||||||
|
duplicate_map->path = cli_safer_strdup(map->path);
|
||||||
|
if (NULL == duplicate_map->path) {
|
||||||
|
status = CL_EMEM;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
duplicate_map->path = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
status = CL_SUCCESS;
|
status = CL_SUCCESS;
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
@ -322,6 +351,10 @@ void free_duplicate_fmap(cl_fmap_t *map)
|
||||||
free(map->name);
|
free(map->name);
|
||||||
map->name = NULL;
|
map->name = NULL;
|
||||||
}
|
}
|
||||||
|
if (NULL != map->path) {
|
||||||
|
free(map->path);
|
||||||
|
map->path = NULL;
|
||||||
|
}
|
||||||
free(map);
|
free(map);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -344,12 +377,15 @@ static void unmap_handle(fmap_t *m)
|
||||||
if (NULL != m->name) {
|
if (NULL != m->name) {
|
||||||
free(m->name);
|
free(m->name);
|
||||||
}
|
}
|
||||||
|
if (NULL != m->path) {
|
||||||
|
free(m->path);
|
||||||
|
}
|
||||||
free((void *)m);
|
free((void *)m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extern cl_fmap_t *cl_fmap_open_handle(void *handle, size_t offset, size_t len,
|
cl_fmap_t *fmap_open_handle(void *handle, size_t offset, size_t len,
|
||||||
clcb_pread pread_cb, int use_aging)
|
clcb_pread pread_cb, int use_aging)
|
||||||
{
|
{
|
||||||
cl_error_t status = CL_EMEM;
|
cl_error_t status = CL_EMEM;
|
||||||
uint64_t pages;
|
uint64_t pages;
|
||||||
|
@ -431,9 +467,9 @@ extern cl_fmap_t *cl_fmap_open_handle(void *handle, size_t offset, size_t len,
|
||||||
m->gets = handle_gets;
|
m->gets = handle_gets;
|
||||||
m->unneed_off = handle_unneed_off;
|
m->unneed_off = handle_unneed_off;
|
||||||
m->handle_is_fd = true;
|
m->handle_is_fd = true;
|
||||||
m->have_md5 = false;
|
|
||||||
m->have_sha1 = false;
|
memset(m->will_need_hash, 0, sizeof(m->will_need_hash));
|
||||||
m->have_sha256 = false;
|
memset(m->have_hash, 0, sizeof(m->have_hash));
|
||||||
|
|
||||||
status = CL_SUCCESS;
|
status = CL_SUCCESS;
|
||||||
|
|
||||||
|
@ -723,7 +759,7 @@ static void unmap_mmap(fmap_t *m)
|
||||||
size_t len = m->pages * m->pgsz;
|
size_t len = m->pages * m->pgsz;
|
||||||
fmap_lock;
|
fmap_lock;
|
||||||
if (munmap((void *)m->data, len) == -1) /* munmap() failed */
|
if (munmap((void *)m->data, len) == -1) /* munmap() failed */
|
||||||
cli_warnmsg("funmap: unable to unmap memory segment at address: %p with length: %zu\n", (void *)m->data, len);
|
cli_warnmsg("fmap_free: unable to unmap memory segment at address: %p with length: %zu\n", (void *)m->data, len);
|
||||||
fmap_unlock;
|
fmap_unlock;
|
||||||
#else
|
#else
|
||||||
UNUSEDPARAM(m);
|
UNUSEDPARAM(m);
|
||||||
|
@ -736,6 +772,9 @@ static void unmap_malloc(fmap_t *m)
|
||||||
if (NULL != m->name) {
|
if (NULL != m->name) {
|
||||||
free(m->name);
|
free(m->name);
|
||||||
}
|
}
|
||||||
|
if (NULL != m->path) {
|
||||||
|
free(m->path);
|
||||||
|
}
|
||||||
free((void *)m);
|
free((void *)m);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -885,11 +924,6 @@ done:
|
||||||
return m;
|
return m;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern cl_fmap_t *cl_fmap_open_memory(const void *start, size_t len)
|
|
||||||
{
|
|
||||||
return (cl_fmap_t *)fmap_open_memory(start, len, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const void *mem_need(fmap_t *m, size_t at, size_t len, int lock)
|
static const void *mem_need(fmap_t *m, size_t at, size_t len, int lock)
|
||||||
{
|
{
|
||||||
UNUSEDPARAM(lock);
|
UNUSEDPARAM(lock);
|
||||||
|
@ -951,10 +985,10 @@ static const void *mem_gets(fmap_t *m, char *dst, size_t *at, size_t max_len)
|
||||||
return dst;
|
return dst;
|
||||||
}
|
}
|
||||||
|
|
||||||
fmap_t *fmap(int fd, off_t offset, size_t len, const char *name)
|
fmap_t *fmap_new(int fd, off_t offset, size_t len, const char *name, const char *path)
|
||||||
{
|
{
|
||||||
int unused;
|
int unused;
|
||||||
return fmap_check_empty(fd, offset, len, &unused, name);
|
return fmap_check_empty(fd, offset, len, &unused, name, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline uint64_t fmap_align_items(uint64_t sz, uint64_t al)
|
static inline uint64_t fmap_align_items(uint64_t sz, uint64_t al)
|
||||||
|
@ -995,7 +1029,7 @@ cl_error_t fmap_dump_to_file(fmap_t *map, const char *filepath, const char *tmpd
|
||||||
|
|
||||||
/* Create a filename prefix that includes the original filename, if available */
|
/* Create a filename prefix that includes the original filename, if available */
|
||||||
if (filepath != NULL) {
|
if (filepath != NULL) {
|
||||||
if (CL_SUCCESS != cli_basename(filepath, strlen(filepath), &filebase)) {
|
if (CL_SUCCESS != cli_basename(filepath, strlen(filepath), &filebase, true /* posix_support_backslash_pathsep */)) {
|
||||||
cli_dbgmsg("fmap_dump_to_file: Unable to determine basename from filepath.\n");
|
cli_dbgmsg("fmap_dump_to_file: Unable to determine basename from filepath.\n");
|
||||||
} else if ((start_offset != 0) && (end_offset != map->real_len)) {
|
} else if ((start_offset != 0) && (end_offset != map->real_len)) {
|
||||||
/* If we're only dumping a portion of the file, include the offsets in the prefix,...
|
/* If we're only dumping a portion of the file, include the offsets in the prefix,...
|
||||||
|
@ -1081,14 +1115,9 @@ int fmap_fd(fmap_t *m)
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void cl_fmap_close(cl_fmap_t *map)
|
cl_error_t fmap_set_hash(fmap_t *map, uint8_t *hash, cli_hash_type_t type)
|
||||||
{
|
{
|
||||||
funmap(map);
|
cl_error_t status = CL_ERROR;
|
||||||
}
|
|
||||||
|
|
||||||
cl_error_t fmap_set_hash(fmap_t *map, unsigned char *hash, cli_hash_type_t type)
|
|
||||||
{
|
|
||||||
cl_error_t status = CL_SUCCESS;
|
|
||||||
|
|
||||||
if (NULL == map) {
|
if (NULL == map) {
|
||||||
cli_errmsg("fmap_set_hash: Attempted to set hash for NULL fmap\n");
|
cli_errmsg("fmap_set_hash: Attempted to set hash for NULL fmap\n");
|
||||||
|
@ -1101,25 +1130,55 @@ cl_error_t fmap_set_hash(fmap_t *map, unsigned char *hash, cli_hash_type_t type)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (type) {
|
if (type >= CLI_HASH_AVAIL_TYPES) {
|
||||||
case CLI_HASH_MD5:
|
cli_errmsg("fmap_set_hash: Unsupported hash type %u\n", type);
|
||||||
memcpy(map->md5, hash, CLI_HASHLEN_MD5);
|
status = CL_EARG;
|
||||||
map->have_md5 = true;
|
goto done;
|
||||||
break;
|
|
||||||
case CLI_HASH_SHA1:
|
|
||||||
memcpy(map->sha1, hash, CLI_HASHLEN_SHA1);
|
|
||||||
map->have_sha1 = true;
|
|
||||||
break;
|
|
||||||
case CLI_HASH_SHA256:
|
|
||||||
memcpy(map->sha256, hash, CLI_HASHLEN_SHA256);
|
|
||||||
map->have_sha256 = true;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
cli_errmsg("fmap_set_hash: Unsupported hash type %u\n", type);
|
|
||||||
status = CL_EARG;
|
|
||||||
goto done;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
memcpy(map->hash[type], hash, cli_hash_len(type));
|
||||||
|
map->have_hash[type] = true;
|
||||||
|
status = CL_SUCCESS;
|
||||||
|
|
||||||
|
if (cli_debug_flag) {
|
||||||
|
// Convert the hash to a hex string for logging
|
||||||
|
char hash_string[CLI_HASHLEN_MAX * 2 + 1] = {0};
|
||||||
|
size_t hash_len = cli_hash_len(type);
|
||||||
|
|
||||||
|
// Convert hash to string.
|
||||||
|
size_t i;
|
||||||
|
for (i = 0; i < hash_len; i++) {
|
||||||
|
sprintf(hash_string + i * 2, "%02x", map->hash[type][i]);
|
||||||
|
}
|
||||||
|
hash_string[hash_len * 2] = 0;
|
||||||
|
|
||||||
|
cli_dbgmsg("fmap_set_hash: set %s hash: %s\n", cli_hash_name(type), hash_string);
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
cl_error_t fmap_will_need_hash_later(fmap_t *map, cli_hash_type_t type)
|
||||||
|
{
|
||||||
|
cl_error_t status = CL_ERROR;
|
||||||
|
|
||||||
|
if (NULL == map) {
|
||||||
|
cli_errmsg("fmap_will_need_hash_later: Attempted to set hash for NULL fmap\n");
|
||||||
|
status = CL_EARG;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type >= CLI_HASH_AVAIL_TYPES) {
|
||||||
|
cli_errmsg("fmap_will_need_hash_later: Unsupported hash type %u\n", type);
|
||||||
|
status = CL_EARG;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set flags */
|
||||||
|
map->will_need_hash[type] = true;
|
||||||
|
status = CL_SUCCESS;
|
||||||
|
|
||||||
done:
|
done:
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
@ -1128,54 +1187,40 @@ cl_error_t fmap_get_hash(fmap_t *map, unsigned char **hash, cli_hash_type_t type
|
||||||
{
|
{
|
||||||
cl_error_t status = CL_ERROR;
|
cl_error_t status = CL_ERROR;
|
||||||
size_t todo, at = 0;
|
size_t todo, at = 0;
|
||||||
void *hashctx = NULL;
|
void *hashctx[CLI_HASH_AVAIL_TYPES] = {NULL};
|
||||||
|
cli_hash_type_t hash_type;
|
||||||
|
|
||||||
todo = map->len;
|
todo = map->len;
|
||||||
|
|
||||||
switch (type) {
|
if (type >= CLI_HASH_AVAIL_TYPES) {
|
||||||
case CLI_HASH_MD5:
|
cli_errmsg("fmap_get_hash: Unsupported hash type %u\n", type);
|
||||||
if (map->have_md5) {
|
status = CL_EARG;
|
||||||
goto complete;
|
goto done;
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CLI_HASH_SHA1:
|
|
||||||
if (map->have_sha1) {
|
|
||||||
goto complete;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case CLI_HASH_SHA256:
|
|
||||||
if (map->have_sha256) {
|
|
||||||
goto complete;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
cli_errmsg("fmap_get_hash: Unsupported hash type %u\n", type);
|
|
||||||
status = CL_EARG;
|
|
||||||
goto done;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If we already have the hash, just return it */
|
||||||
|
if (map->have_hash[type]) {
|
||||||
|
goto complete;
|
||||||
|
}
|
||||||
|
|
||||||
|
map->will_need_hash[type] = true;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Need to calculate the hash.
|
* Need to calculate the requested hash and maybe others, as well.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
switch (type) {
|
/* Initialize hash contexts for all needed hash types */
|
||||||
case CLI_HASH_MD5:
|
for (hash_type = CLI_HASH_MD5; hash_type < CLI_HASH_AVAIL_TYPES; hash_type++) {
|
||||||
hashctx = cl_hash_init("md5");
|
if (map->will_need_hash[hash_type] && !map->have_hash[hash_type]) {
|
||||||
break;
|
const char *hash_name = cli_hash_name(hash_type);
|
||||||
case CLI_HASH_SHA1:
|
|
||||||
hashctx = cl_hash_init("sha1");
|
hashctx[hash_type] = cl_hash_init(hash_name);
|
||||||
break;
|
if (NULL == hashctx[hash_type]) {
|
||||||
case CLI_HASH_SHA256:
|
cli_errmsg("fmap_get_hash: error initializing %s hash context\n", hash_name);
|
||||||
hashctx = cl_hash_init("sha256");
|
status = CL_EARG;
|
||||||
break;
|
goto done;
|
||||||
default:
|
}
|
||||||
cli_errmsg("fmap_get_hash: Unsupported hash type %u\n", type);
|
}
|
||||||
status = CL_EARG;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
if (!(hashctx)) {
|
|
||||||
cli_errmsg("fmap_get_hash: error initializing new md5 hash!\n");
|
|
||||||
goto done;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while (todo) {
|
while (todo) {
|
||||||
|
@ -1191,58 +1236,415 @@ cl_error_t fmap_get_hash(fmap_t *map, unsigned char **hash, cli_hash_type_t type
|
||||||
todo -= readme;
|
todo -= readme;
|
||||||
at += readme;
|
at += readme;
|
||||||
|
|
||||||
if (cl_update_hash(hashctx, (void *)buf, readme)) {
|
for (hash_type = CLI_HASH_MD5; hash_type < CLI_HASH_AVAIL_TYPES; hash_type++) {
|
||||||
cli_errmsg("fmap_get_hash: error calculating hash!\n");
|
if (map->will_need_hash[hash_type] && !map->have_hash[hash_type]) {
|
||||||
status = CL_EREAD;
|
if (cl_update_hash(hashctx[hash_type], buf, readme)) {
|
||||||
goto done;
|
const char *hash_name = cli_hash_name(hash_type);
|
||||||
|
cli_errmsg("fmap_get_hash: error calculating %s hash!\n", hash_name);
|
||||||
|
status = CL_EREAD;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (type) {
|
for (hash_type = CLI_HASH_MD5; hash_type < CLI_HASH_AVAIL_TYPES; hash_type++) {
|
||||||
case CLI_HASH_MD5:
|
if (map->will_need_hash[hash_type] && !map->have_hash[hash_type]) {
|
||||||
cl_finish_hash(hashctx, map->md5);
|
cl_finish_hash(hashctx[hash_type], map->hash[hash_type]);
|
||||||
map->have_md5 = true;
|
map->have_hash[hash_type] = true;
|
||||||
break;
|
|
||||||
case CLI_HASH_SHA1:
|
/* hashctx is finished, don't need to destroy it later */
|
||||||
cl_finish_hash(hashctx, map->sha1);
|
hashctx[hash_type] = NULL;
|
||||||
map->have_sha1 = true;
|
|
||||||
break;
|
if (cli_debug_flag) {
|
||||||
case CLI_HASH_SHA256:
|
// Convert the hash to a hex string for logging
|
||||||
cl_finish_hash(hashctx, map->sha256);
|
char hash_string[CLI_HASHLEN_MAX * 2 + 1] = {0};
|
||||||
map->have_sha256 = true;
|
size_t hash_len = cli_hash_len(hash_type);
|
||||||
break;
|
|
||||||
default:
|
// Convert hash to string.
|
||||||
cli_errmsg("fmap_get_hash: Unsupported hash type %u\n", type);
|
size_t i;
|
||||||
status = CL_EARG;
|
for (i = 0; i < hash_len; i++) {
|
||||||
goto done;
|
sprintf(hash_string + i * 2, "%02x", map->hash[hash_type][i]);
|
||||||
|
}
|
||||||
|
hash_string[hash_len * 2] = 0;
|
||||||
|
|
||||||
|
cli_dbgmsg("fmap_get_hash: calculated %s hash: %s\n", cli_hash_name(hash_type), hash_string);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
hashctx = NULL;
|
|
||||||
|
|
||||||
complete:
|
complete:
|
||||||
|
|
||||||
switch (type) {
|
*hash = map->hash[type];
|
||||||
case CLI_HASH_MD5:
|
status = CL_SUCCESS;
|
||||||
*hash = map->md5;
|
|
||||||
break;
|
done:
|
||||||
case CLI_HASH_SHA1:
|
|
||||||
*hash = map->sha1;
|
for (hash_type = CLI_HASH_MD5; hash_type < CLI_HASH_AVAIL_TYPES; hash_type++) {
|
||||||
break;
|
if (NULL != hashctx[hash_type]) {
|
||||||
case CLI_HASH_SHA256:
|
cl_hash_destroy(hashctx[hash_type]);
|
||||||
*hash = map->sha256;
|
}
|
||||||
break;
|
}
|
||||||
default:
|
|
||||||
cli_errmsg("fmap_get_hash: Unsupported hash type %u\n", type);
|
return status;
|
||||||
status = CL_EARG;
|
}
|
||||||
goto done;
|
|
||||||
|
/*
|
||||||
|
* Public API functions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
extern cl_fmap_t *cl_fmap_open_handle(
|
||||||
|
void *handle,
|
||||||
|
size_t offset,
|
||||||
|
size_t len,
|
||||||
|
clcb_pread pread_cb,
|
||||||
|
int use_aging)
|
||||||
|
{
|
||||||
|
return fmap_open_handle(handle, offset, len, pread_cb, use_aging);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern cl_fmap_t *cl_fmap_open_memory(const void *start, size_t len)
|
||||||
|
{
|
||||||
|
return (cl_fmap_t *)fmap_open_memory(start, len, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern cl_error_t cl_fmap_set_name(cl_fmap_t *map, const char *name)
|
||||||
|
{
|
||||||
|
cl_error_t status = CL_ERROR;
|
||||||
|
|
||||||
|
if (!map || !name) {
|
||||||
|
status = CL_ENULLARG;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(map->name);
|
||||||
|
|
||||||
|
map->name = cli_safer_strdup(name);
|
||||||
|
if (!map->name) {
|
||||||
|
status = CL_EMEM;
|
||||||
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = CL_SUCCESS;
|
status = CL_SUCCESS;
|
||||||
|
|
||||||
done:
|
done:
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
if (NULL != hashctx) {
|
extern cl_error_t cl_fmap_get_name(cl_fmap_t *map, const char **name_out)
|
||||||
cl_hash_destroy(hashctx);
|
{
|
||||||
|
cl_error_t status = CL_ERROR;
|
||||||
|
|
||||||
|
if (!map || !name_out) {
|
||||||
|
status = CL_ENULLARG;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
*name_out = map->name;
|
||||||
|
status = CL_SUCCESS;
|
||||||
|
|
||||||
|
done:
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern cl_error_t cl_fmap_set_path(cl_fmap_t *map, const char *path)
|
||||||
|
{
|
||||||
|
cl_error_t status = CL_ERROR;
|
||||||
|
|
||||||
|
if (!map || !path) {
|
||||||
|
status = CL_ENULLARG;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(map->path);
|
||||||
|
|
||||||
|
map->path = cli_safer_strdup(path);
|
||||||
|
if (!map->path) {
|
||||||
|
status = CL_EMEM;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = CL_SUCCESS;
|
||||||
|
|
||||||
|
done:
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern cl_error_t cl_fmap_get_path(cl_fmap_t *map, const char **path_out, size_t *offset_out, size_t *len_out)
|
||||||
|
{
|
||||||
|
cl_error_t status = CL_ERROR;
|
||||||
|
|
||||||
|
if (!map || !path_out) {
|
||||||
|
status = CL_ENULLARG;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
*path_out = map->path;
|
||||||
|
if (NULL == *path_out) {
|
||||||
|
status = CL_EACCES;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offset_out) {
|
||||||
|
*offset_out = map->offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len_out) {
|
||||||
|
*len_out = map->len;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = CL_SUCCESS;
|
||||||
|
|
||||||
|
done:
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern cl_error_t cl_fmap_get_fd(const cl_fmap_t *map, int *fd_out, size_t *offset_out, size_t *len_out)
|
||||||
|
{
|
||||||
|
cl_error_t status = CL_ERROR;
|
||||||
|
|
||||||
|
if (!map || !fd_out) {
|
||||||
|
status = CL_ENULLARG;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
*fd_out = fmap_fd((fmap_t *)map);
|
||||||
|
if (*fd_out == -1) {
|
||||||
|
status = CL_EACCES;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offset_out) {
|
||||||
|
*offset_out = map->offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len_out) {
|
||||||
|
*len_out = map->len;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = CL_SUCCESS;
|
||||||
|
|
||||||
|
done:
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern cl_error_t cl_fmap_get_size(const cl_fmap_t *map, size_t *size_out)
|
||||||
|
{
|
||||||
|
cl_error_t status = CL_ERROR;
|
||||||
|
|
||||||
|
if (!map || !size_out) {
|
||||||
|
status = CL_ENULLARG;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
*size_out = map->len;
|
||||||
|
status = CL_SUCCESS;
|
||||||
|
|
||||||
|
done:
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern cl_error_t cl_fmap_set_hash(const cl_fmap_t *map, const char *hash_alg, char hash)
|
||||||
|
{
|
||||||
|
cl_error_t status = CL_ERROR;
|
||||||
|
cli_hash_type_t type;
|
||||||
|
|
||||||
|
if (!map || !hash_alg) {
|
||||||
|
status = CL_ENULLARG;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = cli_hash_type_from_name(hash_alg, &type);
|
||||||
|
if (status != CL_SUCCESS) {
|
||||||
|
cli_errmsg("cl_fmap_set_hash: Unknown hash algorithm: %s\n", hash_alg);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type >= CLI_HASH_AVAIL_TYPES) {
|
||||||
|
cli_errmsg("cl_fmap_set_hash: Unsupported hash algorithm: %s\n", hash_alg);
|
||||||
|
status = CL_EARG;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = fmap_set_hash((fmap_t *)map, (uint8_t *)&hash, type);
|
||||||
|
if (status != CL_SUCCESS) {
|
||||||
|
cli_errmsg("cl_fmap_set_hash: Failed to set hash for algorithm: %s\n", hash_alg);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern cl_error_t cl_fmap_have_hash(const cl_fmap_t *map, const char *hash_alg, bool *have_hash_out)
|
||||||
|
{
|
||||||
|
cl_error_t status = CL_ERROR;
|
||||||
|
cli_hash_type_t type;
|
||||||
|
|
||||||
|
if (!map || !hash_alg || !have_hash_out) {
|
||||||
|
status = CL_ENULLARG;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = cli_hash_type_from_name(hash_alg, &type);
|
||||||
|
if (status != CL_SUCCESS) {
|
||||||
|
cli_errmsg("cl_fmap_have_hash: Unknown hash algorithm: %s\n", hash_alg);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type >= CLI_HASH_AVAIL_TYPES) {
|
||||||
|
cli_errmsg("cl_fmap_have_hash: Unsupported hash algorithm: %s\n", hash_alg);
|
||||||
|
status = CL_EARG;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
*have_hash_out = map->have_hash[type];
|
||||||
|
status = CL_SUCCESS;
|
||||||
|
|
||||||
|
done:
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern cl_error_t cl_fmap_will_need_hash_later(const cl_fmap_t *map, const char *hash_alg)
|
||||||
|
{
|
||||||
|
cl_error_t status = CL_ERROR;
|
||||||
|
cli_hash_type_t type;
|
||||||
|
|
||||||
|
if (!map || !hash_alg) {
|
||||||
|
status = CL_ENULLARG;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = cli_hash_type_from_name(hash_alg, &type);
|
||||||
|
if (status != CL_SUCCESS) {
|
||||||
|
cli_errmsg("cl_fmap_will_need_hash_later: Unknown hash algorithm: %s\n", hash_alg);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type >= CLI_HASH_AVAIL_TYPES) {
|
||||||
|
cli_errmsg("cl_fmap_will_need_hash_later: Unsupported hash algorithm: %s\n", hash_alg);
|
||||||
|
status = CL_EARG;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = fmap_will_need_hash_later((fmap_t *)map, type);
|
||||||
|
if (status != CL_SUCCESS) {
|
||||||
|
cli_errmsg("cl_fmap_will_need_hash_later: Failed to indicate need for hash algorithm: %s\n", hash_alg);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = CL_SUCCESS;
|
||||||
|
|
||||||
|
done:
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern cl_error_t cl_fmap_get_hash(const cl_fmap_t *map, const char *hash_alg, char **hash_out)
|
||||||
|
{
|
||||||
|
cl_error_t status = CL_ERROR;
|
||||||
|
cli_hash_type_t type;
|
||||||
|
unsigned char *hash;
|
||||||
|
char *hash_string = NULL;
|
||||||
|
size_t hash_len;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
if (!map || !hash_alg || !hash_out) {
|
||||||
|
status = CL_ENULLARG;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = cli_hash_type_from_name(hash_alg, &type);
|
||||||
|
if (status != CL_SUCCESS) {
|
||||||
|
cli_errmsg("cl_fmap_get_hash: Unknown hash algorithm: %s\n", hash_alg);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type >= CLI_HASH_AVAIL_TYPES) {
|
||||||
|
cli_errmsg("cl_fmap_get_hash: Unsupported hash algorithm: %s\n", hash_alg);
|
||||||
|
status = CL_EARG;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = fmap_get_hash((fmap_t *)map, &hash, type);
|
||||||
|
if (status != CL_SUCCESS) {
|
||||||
|
cli_errmsg("cl_fmap_get_hash: Failed to get hash for algorithm: %s\n", hash_alg);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
hash_len = cli_hash_len(type);
|
||||||
|
|
||||||
|
/* Convert hash to string */
|
||||||
|
hash_string = malloc(hash_len * 2 + 1);
|
||||||
|
if (!hash_string) {
|
||||||
|
cli_errmsg("cl_fmap_get_hash: Failed to allocate memory for hash string\n");
|
||||||
|
status = CL_EMEM;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < hash_len; i++) {
|
||||||
|
sprintf(hash_string + i * 2, "%02x", hash[i]);
|
||||||
|
}
|
||||||
|
hash_string[hash_len * 2] = 0;
|
||||||
|
|
||||||
|
*hash_out = hash_string;
|
||||||
|
status = CL_SUCCESS;
|
||||||
|
|
||||||
|
done:
|
||||||
|
if (status != CL_SUCCESS) {
|
||||||
|
if (NULL != hash_string) {
|
||||||
|
free(hash_string);
|
||||||
|
hash_string = NULL;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extern cl_error_t cl_fmap_get_data(const cl_fmap_t *map, size_t offset, size_t len, const uint8_t **data_out, size_t *data_len_out)
|
||||||
|
{
|
||||||
|
cl_error_t status = CL_ERROR;
|
||||||
|
const uint8_t *data;
|
||||||
|
|
||||||
|
if (!map || !data_out) {
|
||||||
|
status = CL_ENULLARG;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offset > map->len) {
|
||||||
|
cli_errmsg("cl_fmap_get_data: Offset %zu is beyond end of file (file length %zu)\n", offset, map->len);
|
||||||
|
status = CL_EARG;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (len == 0) {
|
||||||
|
// If len is 0, we want to read to the end of the file.
|
||||||
|
len = map->len - offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (offset + len > map->len) {
|
||||||
|
// Adjust len to read only to the end of the file if they asked for too much.
|
||||||
|
len = map->len - offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
data = fmap_need_off_once_len((fmap_t *)map, offset, len, &len);
|
||||||
|
if (!data) {
|
||||||
|
cli_errmsg("cl_fmap_get_data: Failed to get data from fmap\n");
|
||||||
|
status = CL_EREAD;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
*data_out = data;
|
||||||
|
if (data_len_out) {
|
||||||
|
*data_len_out = len;
|
||||||
|
}
|
||||||
|
|
||||||
|
status = CL_SUCCESS;
|
||||||
|
|
||||||
|
done:
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
extern void cl_fmap_close(cl_fmap_t *map)
|
||||||
|
{
|
||||||
|
fmap_free(map);
|
||||||
|
}
|
||||||
|
|
|
@ -55,18 +55,20 @@ struct cl_fmap {
|
||||||
uint64_t pages;
|
uint64_t pages;
|
||||||
uint64_t pgsz;
|
uint64_t pgsz;
|
||||||
uint64_t paged;
|
uint64_t paged;
|
||||||
bool aging; /** indicates if we should age off memory mapped pages */
|
bool aging; /** Indicates if we should age off memory mapped pages */
|
||||||
bool dont_cache_flag; /** indicates if we should not cache scan results for this fmap. Used if limits exceeded */
|
bool dont_cache_flag; /** Indicates if we should not cache scan results for this fmap. Used if limits exceeded */
|
||||||
bool handle_is_fd; /** non-zero if map->handle is an fd. */
|
bool handle_is_fd; /** Non-zero if `map->handle` is an fd. This is needed so that `fmap_fd()` knows if it can
|
||||||
size_t offset; /** file offset representing start of original fmap, if the fmap created reading from a file starting at offset other than 0 */
|
return a file descriptor. If it's some other kind of handle, then `fmap_fd()` has to return -1. */
|
||||||
size_t nested_offset; /** offset from start of original fmap (data) for nested scan. 0 for orig fmap. */
|
size_t offset; /** File offset representing start of original fmap, if the fmap created reading from a file starting at offset other than 0.
|
||||||
size_t real_len; /** len from start of original fmap (data) to end of current (possibly nested) map. */
|
`offset` & `len` are critical information for anyone using the file descriptor/handle */
|
||||||
/* real_len == nested_offset + len.
|
size_t nested_offset; /** Offset from start of original fmap (data) for nested scan. 0 for orig fmap. */
|
||||||
real_len is needed for nested maps because we only reference the original mapping data.
|
size_t real_len; /** Length from start of original fmap (data) to end of current (possibly nested) map.
|
||||||
We convert caller's fmap offsets & lengths to real data offsets using nested_offset & real_len. */
|
`real_len == nested_offset + len`.
|
||||||
|
`real_len` is needed for nested maps because we only reference the original mapping data.
|
||||||
|
We convert caller's fmap offsets & lengths to real data offsets using `nested_offset` & `real_len`. */
|
||||||
|
|
||||||
/* external */
|
/* external */
|
||||||
size_t len; /** length of data from nested_offset, accessible via current fmap */
|
size_t len; /** Length of data from nested_offset, accessible via current fmap */
|
||||||
|
|
||||||
/* real_len = nested_offset + len
|
/* real_len = nested_offset + len
|
||||||
* file_offset = offset + nested_offset + need_offset
|
* file_offset = offset + nested_offset + need_offset
|
||||||
|
@ -84,14 +86,19 @@ struct cl_fmap {
|
||||||
void (*unneed_off)(fmap_t *, size_t at, size_t len);
|
void (*unneed_off)(fmap_t *, size_t at, size_t len);
|
||||||
void *windows_file_handle;
|
void *windows_file_handle;
|
||||||
void *windows_map_handle;
|
void *windows_map_handle;
|
||||||
bool have_md5;
|
|
||||||
unsigned char md5[CLI_HASHLEN_MD5];
|
/* flags to indicate if we should calculate a hash next time we calculate any hashes */
|
||||||
bool have_sha1;
|
bool will_need_hash[CLI_HASH_AVAIL_TYPES];
|
||||||
unsigned char sha1[CLI_HASHLEN_SHA1];
|
|
||||||
bool have_sha256;
|
/* flags to indicate if we have calculated a hash */
|
||||||
unsigned char sha256[CLI_HASHLEN_SHA256];
|
bool have_hash[CLI_HASH_AVAIL_TYPES];
|
||||||
|
|
||||||
|
/* hash values */
|
||||||
|
uint8_t hash[CLI_HASH_AVAIL_TYPES][CLI_HASHLEN_MAX];
|
||||||
|
|
||||||
uint64_t *bitmap;
|
uint64_t *bitmap;
|
||||||
char *name;
|
char *name; /* name of the file, e.g. as recorded in a zip file entry record */
|
||||||
|
char *path; /* path to the file/tempfile, if fmap was created from a file descriptor */
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -101,14 +108,15 @@ struct cl_fmap {
|
||||||
* @param offset Offset into file for start of map.
|
* @param offset Offset into file for start of map.
|
||||||
* @param len Length from offset for size of map.
|
* @param len Length from offset for size of map.
|
||||||
* @param name (optional) Original name of the file (to set fmap name metadata)
|
* @param name (optional) Original name of the file (to set fmap name metadata)
|
||||||
* @return fmap_t* The newly created fmap. Free it with `funmap()`
|
* @param path (optional) Original path of the file (to set fmap path metadata)
|
||||||
|
* @return fmap_t* The newly created fmap. Free it with `fmap_free()`
|
||||||
*/
|
*/
|
||||||
fmap_t *fmap(int fd, off_t offset, size_t len, const char *name);
|
fmap_t *fmap_new(int fd, off_t offset, size_t len, const char *name, const char *path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Create new fmap given a file descriptor.
|
* @brief Create new fmap given a file descriptor.
|
||||||
*
|
*
|
||||||
* This variant of fmap() provides a boolean output variable to indicate on
|
* This variant of fmap_new() provides a boolean output variable to indicate on
|
||||||
* failure if the failure was because the file is empty (not really a failure).
|
* failure if the failure was because the file is empty (not really a failure).
|
||||||
*
|
*
|
||||||
* @param fd File descriptor of file to be mapped.
|
* @param fd File descriptor of file to be mapped.
|
||||||
|
@ -116,9 +124,10 @@ fmap_t *fmap(int fd, off_t offset, size_t len, const char *name);
|
||||||
* @param len Length from offset for size of map.
|
* @param len Length from offset for size of map.
|
||||||
* @param[out] empty Boolean will be non-zero if the file couldn't be mapped because it is empty.
|
* @param[out] empty Boolean will be non-zero if the file couldn't be mapped because it is empty.
|
||||||
* @param name (optional) Original name of the file (to set fmap name metadata)
|
* @param name (optional) Original name of the file (to set fmap name metadata)
|
||||||
* @return fmap_t* The newly created fmap. Free it with `funmap()`
|
* @param path (optional) Original path of the file (to set fmap path metadata)
|
||||||
|
* @return fmap_t* The newly created fmap. Free it with `fmap_free()`
|
||||||
*/
|
*/
|
||||||
fmap_t *fmap_check_empty(int fd, off_t offset, size_t len, int *empty, const char *name);
|
fmap_t *fmap_check_empty(int fd, off_t offset, size_t len, int *empty, const char *name, const char *path);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Create a new fmap given a buffer.
|
* @brief Create a new fmap given a buffer.
|
||||||
|
@ -155,7 +164,7 @@ void free_duplicate_fmap(cl_fmap_t *map);
|
||||||
*
|
*
|
||||||
* @param m The map to be free'd.
|
* @param m The map to be free'd.
|
||||||
*/
|
*/
|
||||||
static inline void funmap(fmap_t *m)
|
static inline void fmap_free(fmap_t *m)
|
||||||
{
|
{
|
||||||
m->unmap(m);
|
m->unmap(m);
|
||||||
}
|
}
|
||||||
|
@ -429,6 +438,22 @@ cl_error_t fmap_dump_to_file(fmap_t *map, const char *filepath, const char *tmpd
|
||||||
*/
|
*/
|
||||||
int fmap_fd(fmap_t *m);
|
int fmap_fd(fmap_t *m);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Indicate that we will want to calculate this hash later.asm
|
||||||
|
*
|
||||||
|
* Set a flag to provide advanced notice that the next time we get a hash and
|
||||||
|
* it has to calculate the hash, it will also calculate this hash.
|
||||||
|
*
|
||||||
|
* This is an optimization so that all hashes may be calculated in one pass
|
||||||
|
* of the file rather than doing multiple passes of the file for each
|
||||||
|
* needed hash.
|
||||||
|
*
|
||||||
|
* @param map The map in question.
|
||||||
|
* @param type The type of hash we'll need.
|
||||||
|
* @return cl_error_t CL_SUCCESS if was able to set the flag, else some error.
|
||||||
|
*/
|
||||||
|
cl_error_t fmap_will_need_hash_later(fmap_t *map, cli_hash_type_t type);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get a pointer to the fmap hash.
|
* @brief Get a pointer to the fmap hash.
|
||||||
*
|
*
|
||||||
|
@ -439,7 +464,7 @@ int fmap_fd(fmap_t *m);
|
||||||
* @param type The type of hash to calculate.
|
* @param type The type of hash to calculate.
|
||||||
* @return cl_error_t CL_SUCCESS if was able to get the hash, else some error.
|
* @return cl_error_t CL_SUCCESS if was able to get the hash, else some error.
|
||||||
*/
|
*/
|
||||||
cl_error_t fmap_get_hash(fmap_t *map, unsigned char **hash, cli_hash_type_t type);
|
cl_error_t fmap_get_hash(fmap_t *map, uint8_t **hash, cli_hash_type_t type);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Set the hash for the fmap that was previously calculated.
|
* @brief Set the hash for the fmap that was previously calculated.
|
||||||
|
@ -449,6 +474,6 @@ cl_error_t fmap_get_hash(fmap_t *map, unsigned char **hash, cli_hash_type_t type
|
||||||
* @param type The type of hash to calculate.
|
* @param type The type of hash to calculate.
|
||||||
* @return cl_error_t CL_SUCCESS if was able to set the hash, else some error.
|
* @return cl_error_t CL_SUCCESS if was able to set the hash, else some error.
|
||||||
*/
|
*/
|
||||||
cl_error_t fmap_set_hash(fmap_t *map, unsigned char *hash, cli_hash_type_t type);
|
cl_error_t fmap_set_hash(fmap_t *map, uint8_t *hash, cli_hash_type_t type);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
* Copyright (C) 2013-2025 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
* Copyright (C) 2013-2025 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||||
* Copyright (C) 2011-2013 Sourcefire, Inc.
|
* Copyright (C) 2011-2013 Sourcefire, Inc.
|
||||||
*
|
*
|
||||||
* Authors: Tomasz Kojm <tkojm@clamav.net>, Aldo Mazzeo, Micah Snyder
|
* Authors: Tomasz Kojm <tkojm@clamav.net>, Aldo Mazzeo, Valerie Snyder
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify
|
* 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
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
|
|
@ -360,7 +360,7 @@ static cl_error_t hfsplus_scanfile(cli_ctx *ctx, hfsPlusVolumeHeader *volHeader,
|
||||||
ext = 0;
|
ext = 0;
|
||||||
/* Dump file, extent by extent */
|
/* Dump file, extent by extent */
|
||||||
do {
|
do {
|
||||||
uint32_t currBlock, endBlock, outputSize = 0;
|
uint32_t currBlock, endBlock;
|
||||||
if (targetSize == 0) {
|
if (targetSize == 0) {
|
||||||
cli_dbgmsg("hfsplus_scanfile: output complete\n");
|
cli_dbgmsg("hfsplus_scanfile: output complete\n");
|
||||||
break;
|
break;
|
||||||
|
@ -423,7 +423,6 @@ static cl_error_t hfsplus_scanfile(cli_ctx *ctx, hfsPlusVolumeHeader *volHeader,
|
||||||
}
|
}
|
||||||
|
|
||||||
targetSize -= to_write;
|
targetSize -= to_write;
|
||||||
outputSize += to_write;
|
|
||||||
currBlock++;
|
currBlock++;
|
||||||
|
|
||||||
if (targetSize == 0) {
|
if (targetSize == 0) {
|
||||||
|
@ -1539,7 +1538,7 @@ cli_dbgmsg("sizeof(hfsNodeDescriptor) is %lu\n", sizeof(hfsNodeDescriptor));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Create temp folder for contents */
|
/* Create temp folder for contents */
|
||||||
if (!(targetdir = cli_gentemp_with_prefix(ctx->sub_tmpdir, "hfsplus-tmp"))) {
|
if (!(targetdir = cli_gentemp_with_prefix(ctx->this_layer_tmpdir, "hfsplus-tmp"))) {
|
||||||
cli_errmsg("cli_scanhfsplus: cli_gentemp failed\n");
|
cli_errmsg("cli_scanhfsplus: cli_gentemp failed\n");
|
||||||
status = CL_ETMPDIR;
|
status = CL_ETMPDIR;
|
||||||
goto done;
|
goto done;
|
||||||
|
|
|
@ -87,7 +87,7 @@ static cl_error_t decompress_and_callback(cli_ctx *ctx, fmap_t *input, size_t at
|
||||||
remain = len;
|
remain = len;
|
||||||
|
|
||||||
/* reserve tempfile for output and callback */
|
/* reserve tempfile for output and callback */
|
||||||
if ((ret = cli_gentempfd(ctx->sub_tmpdir, &tmpname, &ofd)) != CL_SUCCESS) {
|
if ((ret = cli_gentempfd(ctx->this_layer_tmpdir, &tmpname, &ofd)) != CL_SUCCESS) {
|
||||||
cli_errmsg("%s: Can't generate temporary file\n", parent);
|
cli_errmsg("%s: Can't generate temporary file\n", parent);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -302,7 +302,7 @@ cl_error_t cli_hwp5header(cli_ctx *ctx, hwp5_header_t *hwp5)
|
||||||
if (SCAN_COLLECT_METADATA) {
|
if (SCAN_COLLECT_METADATA) {
|
||||||
json_object *header, *flags;
|
json_object *header, *flags;
|
||||||
|
|
||||||
header = cli_jsonobj(ctx->wrkproperty, "Hwp5Header");
|
header = cli_jsonobj(ctx->this_layer_metadata_json, "Hwp5Header");
|
||||||
if (!header) {
|
if (!header) {
|
||||||
cli_errmsg("HWP5.x: No memory for Hwp5Header object\n");
|
cli_errmsg("HWP5.x: No memory for Hwp5Header object\n");
|
||||||
return CL_EMEM;
|
return CL_EMEM;
|
||||||
|
@ -405,23 +405,23 @@ cl_error_t cli_scanhwp5_stream(cli_ctx *ctx, hwp5_header_t *hwp5, char *name, in
|
||||||
return CL_ESTAT;
|
return CL_ESTAT;
|
||||||
}
|
}
|
||||||
|
|
||||||
input = fmap(fd, 0, statbuf.st_size, NULL);
|
input = fmap_new(fd, 0, statbuf.st_size, NULL, filepath);
|
||||||
if (!input) {
|
if (!input) {
|
||||||
cli_errmsg("HWP5.x: Failed to get fmap for input stream\n");
|
cli_errmsg("HWP5.x: Failed to get fmap for input stream\n");
|
||||||
return CL_EMAP;
|
return CL_EMAP;
|
||||||
}
|
}
|
||||||
ret = decompress_and_callback(ctx, input, 0, 0, "HWP5.x", hwp5_cb, NULL);
|
ret = decompress_and_callback(ctx, input, 0, 0, "HWP5.x", hwp5_cb, NULL);
|
||||||
funmap(input);
|
fmap_free(input);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* JSON Output Summary Information */
|
/* JSON Output Summary Information */
|
||||||
if (SCAN_COLLECT_METADATA && ctx->properties != NULL) {
|
if (SCAN_COLLECT_METADATA && ctx->metadata_json != NULL) {
|
||||||
if (name && !strncmp(name, "_5_hwpsummaryinformation", 24)) {
|
if (name && !strncmp(name, "_5_hwpsummaryinformation", 24)) {
|
||||||
cli_dbgmsg("HWP5.x: Detected a '_5_hwpsummaryinformation' stream\n");
|
cli_dbgmsg("HWP5.x: Detected a '_5_hwpsummaryinformation' stream\n");
|
||||||
/* JSONOLE2 - what to do if something breaks? */
|
/* JSONOLE2 - what to do if something breaks? */
|
||||||
if (cli_ole2_summary_json(ctx, fd, 2) == CL_ETIMEOUT)
|
if (cli_ole2_summary_json(ctx, fd, 2, filepath) == CL_ETIMEOUT)
|
||||||
return CL_ETIMEOUT;
|
return CL_ETIMEOUT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -530,7 +530,7 @@ static inline cl_error_t parsehwp3_docinfo(cli_ctx *ctx, size_t offset, struct h
|
||||||
json_object *header, *flags;
|
json_object *header, *flags;
|
||||||
char *str;
|
char *str;
|
||||||
|
|
||||||
header = cli_jsonobj(ctx->wrkproperty, "Hwp3Header");
|
header = cli_jsonobj(ctx->this_layer_metadata_json, "Hwp3Header");
|
||||||
if (!header) {
|
if (!header) {
|
||||||
cli_errmsg("HWP3.x: No memory for Hwp3Header object\n");
|
cli_errmsg("HWP3.x: No memory for Hwp3Header object\n");
|
||||||
return CL_EMEM;
|
return CL_EMEM;
|
||||||
|
@ -600,7 +600,7 @@ static inline cl_error_t parsehwp3_docsummary(cli_ctx *ctx, size_t offset)
|
||||||
return CL_EMAP;
|
return CL_EMAP;
|
||||||
}
|
}
|
||||||
|
|
||||||
summary = cli_jsonobj(ctx->wrkproperty, "Hwp3SummaryInfo");
|
summary = cli_jsonobj(ctx->this_layer_metadata_json, "Hwp3SummaryInfo");
|
||||||
if (!summary) {
|
if (!summary) {
|
||||||
cli_errmsg("HWP3.x: No memory for json object\n");
|
cli_errmsg("HWP3.x: No memory for json object\n");
|
||||||
return CL_EMEM;
|
return CL_EMEM;
|
||||||
|
@ -1514,7 +1514,7 @@ static inline cl_error_t parsehwp3_infoblk_1(cli_ctx *ctx, fmap_t *dmap, size_t
|
||||||
hwp3_debug("HWP3.x: Information Block @ offset %llu\n", infoloc);
|
hwp3_debug("HWP3.x: Information Block @ offset %llu\n", infoloc);
|
||||||
|
|
||||||
if (SCAN_COLLECT_METADATA) {
|
if (SCAN_COLLECT_METADATA) {
|
||||||
infoblk_1 = cli_jsonobj(ctx->wrkproperty, "InfoBlk_1");
|
infoblk_1 = cli_jsonobj(ctx->this_layer_metadata_json, "InfoBlk_1");
|
||||||
if (!infoblk_1) {
|
if (!infoblk_1) {
|
||||||
cli_errmsg("HWP5.x: No memory for information block object\n");
|
cli_errmsg("HWP5.x: No memory for information block object\n");
|
||||||
return CL_EMEM;
|
return CL_EMEM;
|
||||||
|
@ -1752,7 +1752,7 @@ static cl_error_t hwp3_cb(void *cbdata, int fd, const char *filepath, cli_ctx *c
|
||||||
return CL_ESTAT;
|
return CL_ESTAT;
|
||||||
}
|
}
|
||||||
|
|
||||||
map = dmap = fmap(fd, 0, statbuf.st_size, NULL);
|
map = dmap = fmap_new(fd, 0, statbuf.st_size, NULL, filepath);
|
||||||
if (!map) {
|
if (!map) {
|
||||||
cli_errmsg("HWP3.x: Failed to get fmap for uncompressed stream\n");
|
cli_errmsg("HWP3.x: Failed to get fmap for uncompressed stream\n");
|
||||||
return CL_EMAP;
|
return CL_EMAP;
|
||||||
|
@ -1767,14 +1767,14 @@ static cl_error_t hwp3_cb(void *cbdata, int fd, const char *filepath, cli_ctx *c
|
||||||
|
|
||||||
/* Fonts - 7 entries of 2 + (n x 40) bytes where n is the first 2 bytes of the entry */
|
/* Fonts - 7 entries of 2 + (n x 40) bytes where n is the first 2 bytes of the entry */
|
||||||
if (SCAN_COLLECT_METADATA)
|
if (SCAN_COLLECT_METADATA)
|
||||||
fonts = cli_jsonarray(ctx->wrkproperty, "FontCounts");
|
fonts = cli_jsonarray(ctx->this_layer_metadata_json, "FontCounts");
|
||||||
|
|
||||||
for (i = 0; i < 7; i++) {
|
for (i = 0; i < 7; i++) {
|
||||||
uint16_t nfonts;
|
uint16_t nfonts;
|
||||||
|
|
||||||
if (fmap_readn(map, &nfonts, offset, sizeof(nfonts)) != sizeof(nfonts)) {
|
if (fmap_readn(map, &nfonts, offset, sizeof(nfonts)) != sizeof(nfonts)) {
|
||||||
if (dmap)
|
if (dmap)
|
||||||
funmap(dmap);
|
fmap_free(dmap);
|
||||||
return CL_EREAD;
|
return CL_EREAD;
|
||||||
}
|
}
|
||||||
nfonts = le16_to_host(nfonts);
|
nfonts = le16_to_host(nfonts);
|
||||||
|
@ -1787,7 +1787,7 @@ static cl_error_t hwp3_cb(void *cbdata, int fd, const char *filepath, cli_ctx *c
|
||||||
if ((new_offset <= offset) || (new_offset >= map->len)) {
|
if ((new_offset <= offset) || (new_offset >= map->len)) {
|
||||||
cli_errmsg("HWP3.x: Font Entry: number of fonts is too high, invalid. %u\n", nfonts);
|
cli_errmsg("HWP3.x: Font Entry: number of fonts is too high, invalid. %u\n", nfonts);
|
||||||
if (dmap)
|
if (dmap)
|
||||||
funmap(dmap);
|
fmap_free(dmap);
|
||||||
return CL_EPARSE;
|
return CL_EPARSE;
|
||||||
}
|
}
|
||||||
offset = new_offset;
|
offset = new_offset;
|
||||||
|
@ -1796,20 +1796,20 @@ static cl_error_t hwp3_cb(void *cbdata, int fd, const char *filepath, cli_ctx *c
|
||||||
/* Styles - 2 + (n x 238) bytes where n is the first 2 bytes of the section */
|
/* Styles - 2 + (n x 238) bytes where n is the first 2 bytes of the section */
|
||||||
if (fmap_readn(map, &nstyles, offset, sizeof(nstyles)) != sizeof(nstyles)) {
|
if (fmap_readn(map, &nstyles, offset, sizeof(nstyles)) != sizeof(nstyles)) {
|
||||||
if (dmap)
|
if (dmap)
|
||||||
funmap(dmap);
|
fmap_free(dmap);
|
||||||
return CL_EREAD;
|
return CL_EREAD;
|
||||||
}
|
}
|
||||||
nstyles = le16_to_host(nstyles);
|
nstyles = le16_to_host(nstyles);
|
||||||
|
|
||||||
if (SCAN_COLLECT_METADATA)
|
if (SCAN_COLLECT_METADATA)
|
||||||
cli_jsonint(ctx->wrkproperty, "StyleCount", nstyles);
|
cli_jsonint(ctx->this_layer_metadata_json, "StyleCount", nstyles);
|
||||||
|
|
||||||
hwp3_debug("HWP3.x: %u Styles @ offset %zu\n", nstyles, offset);
|
hwp3_debug("HWP3.x: %u Styles @ offset %zu\n", nstyles, offset);
|
||||||
new_offset = offset + (2 + nstyles * 238);
|
new_offset = offset + (2 + nstyles * 238);
|
||||||
if ((new_offset <= offset) || (new_offset >= map->len)) {
|
if ((new_offset <= offset) || (new_offset >= map->len)) {
|
||||||
cli_errmsg("HWP3.x: Font Entry: number of font styles is too high, invalid. %u\n", nstyles);
|
cli_errmsg("HWP3.x: Font Entry: number of font styles is too high, invalid. %u\n", nstyles);
|
||||||
if (dmap)
|
if (dmap)
|
||||||
funmap(dmap);
|
fmap_free(dmap);
|
||||||
return CL_EPARSE;
|
return CL_EPARSE;
|
||||||
}
|
}
|
||||||
offset += (2 + nstyles * 238);
|
offset += (2 + nstyles * 238);
|
||||||
|
@ -1821,12 +1821,12 @@ static cl_error_t hwp3_cb(void *cbdata, int fd, const char *filepath, cli_ctx *c
|
||||||
/* return is never a virus */
|
/* return is never a virus */
|
||||||
if (ret != CL_SUCCESS) {
|
if (ret != CL_SUCCESS) {
|
||||||
if (dmap)
|
if (dmap)
|
||||||
funmap(dmap);
|
fmap_free(dmap);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SCAN_COLLECT_METADATA)
|
if (SCAN_COLLECT_METADATA)
|
||||||
cli_jsonint(ctx->wrkproperty, "ParagraphCount", p);
|
cli_jsonint(ctx->this_layer_metadata_json, "ParagraphCount", p);
|
||||||
|
|
||||||
last = 0;
|
last = 0;
|
||||||
/* 'additional information block #1's - attachments and media */
|
/* 'additional information block #1's - attachments and media */
|
||||||
|
@ -1840,7 +1840,7 @@ static cl_error_t hwp3_cb(void *cbdata, int fd, const char *filepath, cli_ctx *c
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dmap)
|
if (dmap)
|
||||||
funmap(dmap);
|
fmap_free(dmap);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1887,7 +1887,7 @@ cl_error_t cli_scanhwp3(cli_ctx *ctx)
|
||||||
if (docinfo.di_compressed)
|
if (docinfo.di_compressed)
|
||||||
ret = decompress_and_callback(ctx, ctx->fmap, offset, 0, "HWP3.x", hwp3_cb, NULL);
|
ret = decompress_and_callback(ctx, ctx->fmap, offset, 0, "HWP3.x", hwp3_cb, NULL);
|
||||||
else
|
else
|
||||||
ret = hwp3_cb(&offset, 0, ctx->sub_filepath, ctx);
|
ret = hwp3_cb(&offset, 0, ctx->fmap->path, ctx);
|
||||||
|
|
||||||
if (ret != CL_SUCCESS)
|
if (ret != CL_SUCCESS)
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -1993,7 +1993,7 @@ static cl_error_t hwpml_binary_cb(int fd, const char *filepath, cli_ctx *ctx, in
|
||||||
return CL_ESTAT;
|
return CL_ESTAT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(input = fmap(fd, 0, statbuf.st_size, NULL))) {
|
if (!(input = fmap_new(fd, 0, statbuf.st_size, NULL, filepath))) {
|
||||||
cli_errmsg("HWPML: Failed to get fmap for binary data\n");
|
cli_errmsg("HWPML: Failed to get fmap for binary data\n");
|
||||||
return CL_EMAP;
|
return CL_EMAP;
|
||||||
}
|
}
|
||||||
|
@ -2001,19 +2001,19 @@ static cl_error_t hwpml_binary_cb(int fd, const char *filepath, cli_ctx *ctx, in
|
||||||
/* send data for base64 conversion - TODO: what happens with really big files? */
|
/* send data for base64 conversion - TODO: what happens with really big files? */
|
||||||
if (!(instream = fmap_need_off_once(input, 0, input->len))) {
|
if (!(instream = fmap_need_off_once(input, 0, input->len))) {
|
||||||
cli_errmsg("HWPML: Failed to get input stream from binary data\n");
|
cli_errmsg("HWPML: Failed to get input stream from binary data\n");
|
||||||
funmap(input);
|
fmap_free(input);
|
||||||
return CL_EMAP;
|
return CL_EMAP;
|
||||||
}
|
}
|
||||||
|
|
||||||
decoded = (char *)cl_base64_decode((char *)instream, input->len, NULL, &decodedlen, 0);
|
decoded = (char *)cl_base64_decode((char *)instream, input->len, NULL, &decodedlen, 0);
|
||||||
funmap(input);
|
fmap_free(input);
|
||||||
if (!decoded) {
|
if (!decoded) {
|
||||||
cli_errmsg("HWPML: Failed to get base64 decode binary data\n");
|
cli_errmsg("HWPML: Failed to get base64 decode binary data\n");
|
||||||
return cli_magic_scan_desc(fd, filepath, ctx, NULL, LAYER_ATTRIBUTES_NONE);
|
return cli_magic_scan_desc(fd, filepath, ctx, NULL, LAYER_ATTRIBUTES_NONE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* open file for writing and scanning */
|
/* open file for writing and scanning */
|
||||||
if ((ret = cli_gentempfd(ctx->sub_tmpdir, &tempfile, &df)) != CL_SUCCESS) {
|
if ((ret = cli_gentempfd(ctx->this_layer_tmpdir, &tempfile, &df)) != CL_SUCCESS) {
|
||||||
cli_warnmsg("HWPML: Failed to create temporary file for decoded stream scanning\n");
|
cli_warnmsg("HWPML: Failed to create temporary file for decoded stream scanning\n");
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -2045,14 +2045,14 @@ static cl_error_t hwpml_binary_cb(int fd, const char *filepath, cli_ctx *ctx, in
|
||||||
goto hwpml_end;
|
goto hwpml_end;
|
||||||
}
|
}
|
||||||
|
|
||||||
input = fmap(fd, 0, statbuf.st_size, NULL);
|
input = fmap_new(fd, 0, statbuf.st_size, NULL, filepath);
|
||||||
if (!input) {
|
if (!input) {
|
||||||
cli_errmsg("HWPML: Failed to get fmap for binary data\n");
|
cli_errmsg("HWPML: Failed to get fmap for binary data\n");
|
||||||
ret = CL_EMAP;
|
ret = CL_EMAP;
|
||||||
goto hwpml_end;
|
goto hwpml_end;
|
||||||
}
|
}
|
||||||
ret = decompress_and_callback(ctx, input, 0, 0, "HWPML", hwpml_scan_cb, NULL);
|
ret = decompress_and_callback(ctx, input, 0, 0, "HWPML", hwpml_scan_cb, NULL);
|
||||||
funmap(input);
|
fmap_free(input);
|
||||||
} else {
|
} else {
|
||||||
if (fd == df) { /* fd is a decoded tempfile */
|
if (fd == df) { /* fd is a decoded tempfile */
|
||||||
ret = hwpml_scan_cb(NULL, fd, tempfile, ctx);
|
ret = hwpml_scan_cb(NULL, fd, tempfile, ctx);
|
||||||
|
@ -2092,7 +2092,7 @@ cl_error_t cli_scanhwpml(cli_ctx *ctx)
|
||||||
if (!reader) {
|
if (!reader) {
|
||||||
cli_dbgmsg("cli_scanhwpml: cannot initialize xmlReader\n");
|
cli_dbgmsg("cli_scanhwpml: cannot initialize xmlReader\n");
|
||||||
|
|
||||||
ret = cli_json_parse_error(ctx->wrkproperty, "HWPML_ERROR_XML_READER_IO");
|
ret = cli_json_parse_error(ctx->this_layer_metadata_json, "HWPML_ERROR_XML_READER_IO");
|
||||||
|
|
||||||
return ret; // libxml2 failed!
|
return ret; // libxml2 failed!
|
||||||
}
|
}
|
||||||
|
|
|
@ -250,7 +250,7 @@ cl_error_t cli_scanishield_msi(cli_ctx *ctx, off_t off)
|
||||||
|
|
||||||
/* FIXMEISHIELD: cleanup the spam below */
|
/* FIXMEISHIELD: cleanup the spam below */
|
||||||
cli_dbgmsg("ishield-msi: File %s (csize: %llx, unk1:%x unk2:%x unk3:%x unk4:%x unk5:%x unk6:%x unk7:%x unk8:%x unk9:%x unk10:%x unk11:%x)\n", key, (long long)csize, fb.unk1, fb.unk2, fb.unk3, fb.unk4, fb.unk5, fb.unk6, fb.unk7, fb.unk8, fb.unk9, fb.unk10, fb.unk11);
|
cli_dbgmsg("ishield-msi: File %s (csize: %llx, unk1:%x unk2:%x unk3:%x unk4:%x unk5:%x unk6:%x unk7:%x unk8:%x unk9:%x unk10:%x unk11:%x)\n", key, (long long)csize, fb.unk1, fb.unk2, fb.unk3, fb.unk4, fb.unk5, fb.unk6, fb.unk7, fb.unk8, fb.unk9, fb.unk10, fb.unk11);
|
||||||
if (!(tempfile = cli_gentemp(ctx->sub_tmpdir))) {
|
if (!(tempfile = cli_gentemp(ctx->this_layer_tmpdir))) {
|
||||||
if (NULL != filename) {
|
if (NULL != filename) {
|
||||||
free(filename);
|
free(filename);
|
||||||
}
|
}
|
||||||
|
@ -491,7 +491,7 @@ static cl_error_t is_dump_and_scan(cli_ctx *ctx, off_t off, size_t fsize)
|
||||||
return CL_SUCCESS;
|
return CL_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(fname = cli_gentemp(ctx->sub_tmpdir))) {
|
if (!(fname = cli_gentemp(ctx->this_layer_tmpdir))) {
|
||||||
return CL_EMEM;
|
return CL_EMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -751,7 +751,7 @@ static cl_error_t is_extract_cab(cli_ctx *ctx, uint64_t off, uint64_t size, uint
|
||||||
return CL_EMEM;
|
return CL_EMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(tempfile = cli_gentemp(ctx->sub_tmpdir))) {
|
if (!(tempfile = cli_gentemp(ctx->this_layer_tmpdir))) {
|
||||||
free(outbuf);
|
free(outbuf);
|
||||||
return CL_EMEM;
|
return CL_EMEM;
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,7 +60,7 @@ static cl_error_t iso_scan_file(const iso9660_t *iso, unsigned int block, unsign
|
||||||
int fd = -1;
|
int fd = -1;
|
||||||
cl_error_t ret = CL_SUCCESS;
|
cl_error_t ret = CL_SUCCESS;
|
||||||
|
|
||||||
if (cli_gentempfd(iso->ctx->sub_tmpdir, &tmpf, &fd) != CL_SUCCESS) {
|
if (cli_gentempfd(iso->ctx->this_layer_tmpdir, &tmpf, &fd) != CL_SUCCESS) {
|
||||||
return CL_ETMPFILE;
|
return CL_ETMPFILE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -225,6 +225,39 @@ cl_error_t cli_jsonint64(json_object *obj, const char *key, int64_t i)
|
||||||
return CL_SUCCESS;
|
return CL_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
cl_error_t cli_jsonuint64(json_object *obj, const char *key, uint64_t i)
|
||||||
|
{
|
||||||
|
json_type objty;
|
||||||
|
json_object *fpobj;
|
||||||
|
if (NULL == obj) {
|
||||||
|
cli_dbgmsg("json: no parent object specified to cli_jsonuint64\n");
|
||||||
|
return CL_ENULLARG;
|
||||||
|
}
|
||||||
|
objty = json_object_get_type(obj);
|
||||||
|
|
||||||
|
if (objty == json_type_object) {
|
||||||
|
if (NULL == key) {
|
||||||
|
cli_dbgmsg("json: null string specified as key to cli_jsonuint64\n");
|
||||||
|
return CL_ENULLARG;
|
||||||
|
}
|
||||||
|
} else if (objty != json_type_array) {
|
||||||
|
return CL_EARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
fpobj = json_object_new_uint64(i);
|
||||||
|
if (NULL == fpobj) {
|
||||||
|
cli_errmsg("json: no memory for json int object.\n");
|
||||||
|
return CL_EMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (objty == json_type_object)
|
||||||
|
json_object_object_add(obj, key, fpobj);
|
||||||
|
else if (objty == json_type_array)
|
||||||
|
json_object_array_add(obj, fpobj);
|
||||||
|
|
||||||
|
return CL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
cl_error_t cli_jsonbool(json_object *obj, const char *key, int i)
|
cl_error_t cli_jsonbool(json_object *obj, const char *key, int i)
|
||||||
{
|
{
|
||||||
json_type objty;
|
json_type objty;
|
||||||
|
|
|
@ -41,6 +41,7 @@ cl_error_t cli_jsonstr(json_object *obj, const char *key, const char *s);
|
||||||
cl_error_t cli_jsonstrlen(json_object *obj, const char *key, const char *s, int len);
|
cl_error_t cli_jsonstrlen(json_object *obj, const char *key, const char *s, int len);
|
||||||
cl_error_t cli_jsonint(json_object *obj, const char *key, int32_t i);
|
cl_error_t cli_jsonint(json_object *obj, const char *key, int32_t i);
|
||||||
cl_error_t cli_jsonint64(json_object *obj, const char *key, int64_t i);
|
cl_error_t cli_jsonint64(json_object *obj, const char *key, int64_t i);
|
||||||
|
cl_error_t cli_jsonuint64(json_object *obj, const char *key, uint64_t i);
|
||||||
cl_error_t cli_jsonbool(json_object *obj, const char *key, int i);
|
cl_error_t cli_jsonbool(json_object *obj, const char *key, int i);
|
||||||
cl_error_t cli_jsondouble(json_object *obj, const char *key, double d);
|
cl_error_t cli_jsondouble(json_object *obj, const char *key, double d);
|
||||||
|
|
||||||
|
|
|
@ -68,6 +68,28 @@ CLAMAV_PUBLIC {
|
||||||
cl_engine_set_clcb_vba;
|
cl_engine_set_clcb_vba;
|
||||||
cl_cvdunpack_ex;
|
cl_cvdunpack_ex;
|
||||||
cl_cvdverify_ex;
|
cl_cvdverify_ex;
|
||||||
|
cl_scandesc_ex;
|
||||||
|
cl_scanmap_ex;
|
||||||
|
cl_scanfile_ex;
|
||||||
|
cl_fmap_set_name;
|
||||||
|
cl_fmap_get_name;
|
||||||
|
cl_fmap_set_path;
|
||||||
|
cl_fmap_get_path;
|
||||||
|
cl_fmap_get_fd;
|
||||||
|
cl_fmap_get_size;
|
||||||
|
cl_fmap_set_hash;
|
||||||
|
cl_fmap_have_hash;
|
||||||
|
cl_fmap_will_need_hash_later;
|
||||||
|
cl_fmap_get_hash;
|
||||||
|
cl_fmap_get_data;
|
||||||
|
cl_scan_layer_get_fmap;
|
||||||
|
cl_scan_layer_get_parent_layer;
|
||||||
|
cl_scan_layer_get_type;
|
||||||
|
cl_scan_layer_get_recursion_level;
|
||||||
|
cl_scan_layer_get_object_id;
|
||||||
|
cl_scan_layer_get_last_alert;
|
||||||
|
cl_scan_layer_get_attributes;
|
||||||
|
cl_engine_set_scan_callback;
|
||||||
};
|
};
|
||||||
CLAMAV_PRIVATE {
|
CLAMAV_PRIVATE {
|
||||||
global:
|
global:
|
||||||
|
@ -224,7 +246,7 @@ CLAMAV_PRIVATE {
|
||||||
cli_bytecode_done;
|
cli_bytecode_done;
|
||||||
cli_bytecode_debug;
|
cli_bytecode_debug;
|
||||||
cli_hex2ui;
|
cli_hex2ui;
|
||||||
fmap;
|
fmap_new;
|
||||||
cli_bytecode_context_set_trace;
|
cli_bytecode_context_set_trace;
|
||||||
cli_bytecode_debug_printsrc;
|
cli_bytecode_debug_printsrc;
|
||||||
cli_bytecode_printversion;
|
cli_bytecode_printversion;
|
||||||
|
@ -296,6 +318,7 @@ CLAMAV_PRIVATE {
|
||||||
cli_checklimits;
|
cli_checklimits;
|
||||||
cli_matchmeta;
|
cli_matchmeta;
|
||||||
cli_cvdunpack_and_verify;
|
cli_cvdunpack_and_verify;
|
||||||
|
cli_cvdverify;
|
||||||
|
|
||||||
__cli_strcasestr;
|
__cli_strcasestr;
|
||||||
__cli_strndup;
|
__cli_strndup;
|
||||||
|
|
|
@ -133,7 +133,7 @@ static void mspack_fmap_close(struct mspack_file *file)
|
||||||
static int mspack_fmap_read(struct mspack_file *file, void *buffer, int bytes)
|
static int mspack_fmap_read(struct mspack_file *file, void *buffer, int bytes)
|
||||||
{
|
{
|
||||||
struct mspack_handle *mspack_handle = (struct mspack_handle *)file;
|
struct mspack_handle *mspack_handle = (struct mspack_handle *)file;
|
||||||
off_t offset;
|
size_t offset;
|
||||||
size_t count;
|
size_t count;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -150,7 +150,7 @@ static int mspack_fmap_read(struct mspack_file *file, void *buffer, int bytes)
|
||||||
/* Use fmap */
|
/* Use fmap */
|
||||||
offset = mspack_handle->offset + mspack_handle->org;
|
offset = mspack_handle->offset + mspack_handle->org;
|
||||||
|
|
||||||
count = fmap_readn(mspack_handle->fmap, buffer, (size_t)offset, (size_t)bytes);
|
count = fmap_readn(mspack_handle->fmap, buffer, offset, (size_t)bytes);
|
||||||
if (count == (size_t)-1) {
|
if (count == (size_t)-1) {
|
||||||
cli_dbgmsg("%s() %d requested %d bytes, read failed (-1)\n", __func__, __LINE__, bytes);
|
cli_dbgmsg("%s() %d requested %d bytes, read failed (-1)\n", __func__, __LINE__, bytes);
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -163,7 +163,7 @@ static int mspack_fmap_read(struct mspack_file *file, void *buffer, int bytes)
|
||||||
return (int)count;
|
return (int)count;
|
||||||
} else {
|
} else {
|
||||||
/* Use file descriptor */
|
/* Use file descriptor */
|
||||||
count = fread(buffer, bytes, 1, mspack_handle->f);
|
count = fread(buffer, (size_t)bytes, 1, mspack_handle->f);
|
||||||
if (count < 1) {
|
if (count < 1) {
|
||||||
cli_dbgmsg("%s() %d requested %d bytes, read failed (%zu)\n", __func__, __LINE__, bytes, count);
|
cli_dbgmsg("%s() %d requested %d bytes, read failed (%zu)\n", __func__, __LINE__, bytes, count);
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -340,18 +340,83 @@ static struct mspack_system mspack_sys_fmap_ops = {
|
||||||
.copy = mspack_fmap_copy,
|
.copy = mspack_fmap_copy,
|
||||||
};
|
};
|
||||||
|
|
||||||
cl_error_t cli_scanmscab(cli_ctx *ctx, off_t sfx_offset)
|
cl_error_t cli_mscab_header_check(cli_ctx *ctx, size_t offset, size_t *size)
|
||||||
|
{
|
||||||
|
cl_error_t status = CL_EFORMAT;
|
||||||
|
|
||||||
|
struct mscab_decompressor *cab_d = NULL;
|
||||||
|
struct mscabd_cabinet *cab_h = NULL;
|
||||||
|
struct mspack_name mspack_fmap = {0};
|
||||||
|
struct mspack_system_ex ops_ex = {0};
|
||||||
|
|
||||||
|
if (NULL == ctx || NULL == size) {
|
||||||
|
cli_dbgmsg("%s() invalid argument\n", __func__);
|
||||||
|
status = CL_EARG;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
*size = 0;
|
||||||
|
mspack_fmap.fmap = ctx->fmap;
|
||||||
|
|
||||||
|
if (offset > INT32_MAX) {
|
||||||
|
cli_dbgmsg("%s() offset too large %zu\n", __func__, offset);
|
||||||
|
status = CL_EFORMAT;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
mspack_fmap.org = (off_t)offset;
|
||||||
|
|
||||||
|
ops_ex.ops = mspack_sys_fmap_ops;
|
||||||
|
|
||||||
|
cab_d = mspack_create_cab_decompressor(&ops_ex.ops);
|
||||||
|
if (NULL == cab_d) {
|
||||||
|
cli_dbgmsg("%s() failed at %d\n", __func__, __LINE__);
|
||||||
|
status = CL_EUNPACK;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
cab_h = cab_d->open(cab_d, (char *)&mspack_fmap);
|
||||||
|
if (NULL == cab_h) {
|
||||||
|
cli_dbgmsg("%s() failed at %d\n", __func__, __LINE__);
|
||||||
|
status = CL_EFORMAT;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
*size = (size_t)cab_h->length;
|
||||||
|
|
||||||
|
cli_dbgmsg("%s(): Successfully read CAB header for CAB of size %zu\n", __func__, *size);
|
||||||
|
status = CL_SUCCESS;
|
||||||
|
|
||||||
|
done:
|
||||||
|
if (NULL != cab_d) {
|
||||||
|
if (NULL != cab_h) {
|
||||||
|
cab_d->close(cab_d, cab_h);
|
||||||
|
}
|
||||||
|
mspack_destroy_cab_decompressor(cab_d);
|
||||||
|
}
|
||||||
|
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
cl_error_t cli_scanmscab(cli_ctx *ctx, size_t sfx_offset)
|
||||||
{
|
{
|
||||||
cl_error_t ret = CL_SUCCESS;
|
cl_error_t ret = CL_SUCCESS;
|
||||||
struct mscab_decompressor *cab_d = NULL;
|
struct mscab_decompressor *cab_d = NULL;
|
||||||
struct mscabd_cabinet *cab_h = NULL;
|
struct mscabd_cabinet *cab_h = NULL;
|
||||||
struct mscabd_file *cab_f = NULL;
|
struct mscabd_file *cab_f = NULL;
|
||||||
int files;
|
int files;
|
||||||
struct mspack_name mspack_fmap = {
|
struct mspack_name mspack_fmap = {0};
|
||||||
.fmap = ctx->fmap,
|
struct mspack_system_ex ops_ex = {0};
|
||||||
.org = sfx_offset,
|
|
||||||
};
|
mspack_fmap.fmap = ctx->fmap;
|
||||||
struct mspack_system_ex ops_ex;
|
|
||||||
|
if (sfx_offset > INT32_MAX) {
|
||||||
|
cli_dbgmsg("%s() offset too large %zu\n", __func__, sfx_offset);
|
||||||
|
ret = CL_EFORMAT;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
mspack_fmap.org = (off_t)sfx_offset;
|
||||||
|
|
||||||
char *tmp_fname = NULL;
|
char *tmp_fname = NULL;
|
||||||
bool tempfile_exists = false;
|
bool tempfile_exists = false;
|
||||||
|
@ -417,7 +482,7 @@ cl_error_t cli_scanmscab(cli_ctx *ctx, off_t sfx_offset)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tmp_fname = cli_gentemp(ctx->sub_tmpdir);
|
tmp_fname = cli_gentemp(ctx->this_layer_tmpdir);
|
||||||
if (!tmp_fname) {
|
if (!tmp_fname) {
|
||||||
ret = CL_EMEM;
|
ret = CL_EMEM;
|
||||||
goto done;
|
goto done;
|
||||||
|
@ -546,7 +611,7 @@ cl_error_t cli_scanmschm(cli_ctx *ctx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tmp_fname = cli_gentemp(ctx->sub_tmpdir);
|
tmp_fname = cli_gentemp(ctx->this_layer_tmpdir);
|
||||||
if (!tmp_fname) {
|
if (!tmp_fname) {
|
||||||
ret = CL_EMEM;
|
ret = CL_EMEM;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -10,7 +10,31 @@
|
||||||
#ifndef __LIBMSPACK_H__
|
#ifndef __LIBMSPACK_H__
|
||||||
#define __LIBMSPACK_H__
|
#define __LIBMSPACK_H__
|
||||||
|
|
||||||
int cli_scanmscab(cli_ctx *ctx, off_t sfx_offset);
|
/**
|
||||||
int cli_scanmschm(cli_ctx *ctx);
|
* @brief Check the CAB header for validity.
|
||||||
|
*
|
||||||
|
* @param fmap The fmap containing the CAB file.
|
||||||
|
* @param offset Offset of the start of a CAB file within the current fmap.
|
||||||
|
* @param size The size of the CAB file.
|
||||||
|
* @return cl_error_t
|
||||||
|
*/
|
||||||
|
cl_error_t cli_mscab_header_check(cli_ctx *ctx, size_t offset, size_t *size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Open and extract a Microsoft CAB file, scanning each extracted file.
|
||||||
|
*
|
||||||
|
* @param ctx Scan context
|
||||||
|
* @param sfx_offset Offset of the start of a CAB file within the current fmap.
|
||||||
|
* @return cl_error_t CL_SUCCESS on success, or an error code on failure.
|
||||||
|
*/
|
||||||
|
cl_error_t cli_scanmscab(cli_ctx *ctx, size_t sfx_offset);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Open and extract a Microsoft CHM file, scanning each extracted file.
|
||||||
|
*
|
||||||
|
* @param ctx Scan context
|
||||||
|
* @return cl_error_t CL_SUCCESS on success, or an error code on failure.
|
||||||
|
*/
|
||||||
|
cl_error_t cli_scanmschm(cli_ctx *ctx);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -25,15 +25,48 @@
|
||||||
typedef enum cli_hash_type {
|
typedef enum cli_hash_type {
|
||||||
CLI_HASH_MD5 = 0,
|
CLI_HASH_MD5 = 0,
|
||||||
CLI_HASH_SHA1,
|
CLI_HASH_SHA1,
|
||||||
CLI_HASH_SHA256,
|
CLI_HASH_SHA2_256,
|
||||||
|
CLI_HASH_SHA2_384,
|
||||||
/* new hash types go above this line */
|
CLI_HASH_SHA2_512,
|
||||||
CLI_HASH_AVAIL_TYPES
|
|
||||||
} cli_hash_type_t;
|
} cli_hash_type_t;
|
||||||
|
|
||||||
#define CLI_HASHLEN_MD5 16
|
#define CLI_HASH_AVAIL_TYPES (CLI_HASH_SHA2_256 + 1)
|
||||||
#define CLI_HASHLEN_SHA1 20
|
|
||||||
#define CLI_HASHLEN_SHA256 32
|
/**
|
||||||
#define CLI_HASHLEN_MAX 32
|
* @brief Get the name of the hash type as a string.
|
||||||
|
*
|
||||||
|
* @param type The hash type.
|
||||||
|
* @return char* The name of the hash type.
|
||||||
|
*/
|
||||||
|
const char* cli_hash_name(cli_hash_type_t type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get OpenSSL's name of the hash type as a string.
|
||||||
|
*
|
||||||
|
* Needed because older versions of OpenSSL aren't familiar with "sha2-256",
|
||||||
|
* "sha2-384", and "sha2-512".
|
||||||
|
*
|
||||||
|
* @param alg The name of the hash algorithm.
|
||||||
|
* @return char* The OpenSSL name of the hash algorithm.
|
||||||
|
*/
|
||||||
|
const char *to_openssl_alg(const char *alg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the size of the hash type.
|
||||||
|
*
|
||||||
|
* @param type The hash type.
|
||||||
|
* @return size_t The size of the hash type.
|
||||||
|
*/
|
||||||
|
size_t cli_hash_len(cli_hash_type_t type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Get the hash type from its name.
|
||||||
|
*
|
||||||
|
* @param name The name of the hash type.
|
||||||
|
* @return cli_hash_type_t The hash type.
|
||||||
|
*/
|
||||||
|
cl_error_t cli_hash_type_from_name(const char* name, cli_hash_type_t* type_out);
|
||||||
|
|
||||||
|
#define CLI_HASHLEN_MAX SHA256_HASH_SIZE
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -26,14 +26,109 @@
|
||||||
#include "others.h"
|
#include "others.h"
|
||||||
#include "str.h"
|
#include "str.h"
|
||||||
|
|
||||||
int hm_addhash_str(struct cli_matcher *root, const char *strhash, uint32_t size, const char *virusname)
|
const char *cli_hash_name(cli_hash_type_t type)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case CLI_HASH_MD5:
|
||||||
|
return "md5";
|
||||||
|
case CLI_HASH_SHA1:
|
||||||
|
return "sha1";
|
||||||
|
case CLI_HASH_SHA2_256:
|
||||||
|
return "sha2-256";
|
||||||
|
case CLI_HASH_SHA2_384:
|
||||||
|
return "sha2-384";
|
||||||
|
case CLI_HASH_SHA2_512:
|
||||||
|
return "sha2-512";
|
||||||
|
default:
|
||||||
|
return "unknown";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *to_openssl_alg(const char *alg) {
|
||||||
|
cl_error_t ret;
|
||||||
|
cli_hash_type_t type;
|
||||||
|
|
||||||
|
ret = cli_hash_type_from_name(alg, &type);
|
||||||
|
if (CL_SUCCESS != ret) {
|
||||||
|
cli_dbgmsg("to_openssl_alg: unknown hash type %s\n", alg);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case CLI_HASH_MD5:
|
||||||
|
return "md5";
|
||||||
|
case CLI_HASH_SHA1:
|
||||||
|
return "sha1";
|
||||||
|
#if OPENSSL_VERSION_MAJOR >= 3
|
||||||
|
case CLI_HASH_SHA2_256:
|
||||||
|
return "sha2-256";
|
||||||
|
case CLI_HASH_SHA2_384:
|
||||||
|
return "sha2-384";
|
||||||
|
case CLI_HASH_SHA2_512:
|
||||||
|
return "sha2-512";
|
||||||
|
#else
|
||||||
|
case CLI_HASH_SHA2_256:
|
||||||
|
return "sha256";
|
||||||
|
case CLI_HASH_SHA2_384:
|
||||||
|
return "sha384";
|
||||||
|
case CLI_HASH_SHA2_512:
|
||||||
|
return "sha512";
|
||||||
|
#endif
|
||||||
|
default:
|
||||||
|
cli_dbgmsg("to_openssl_alg: unknown hash type %d\n", type);
|
||||||
|
return NULL; // Unsupported hash type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t cli_hash_len(cli_hash_type_t type)
|
||||||
|
{
|
||||||
|
switch (type) {
|
||||||
|
case CLI_HASH_MD5:
|
||||||
|
return MD5_HASH_SIZE;
|
||||||
|
case CLI_HASH_SHA1:
|
||||||
|
return SHA1_HASH_SIZE;
|
||||||
|
case CLI_HASH_SHA2_256:
|
||||||
|
return SHA256_HASH_SIZE;
|
||||||
|
case CLI_HASH_SHA2_384:
|
||||||
|
return SHA384_HASH_SIZE;
|
||||||
|
case CLI_HASH_SHA2_512:
|
||||||
|
return SHA512_HASH_SIZE;
|
||||||
|
default:
|
||||||
|
return 0; // Invalid type
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cl_error_t cli_hash_type_from_name(const char *name, cli_hash_type_t *type_out)
|
||||||
|
{
|
||||||
|
if (!name || !type_out) {
|
||||||
|
return CL_ENULLARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strcasecmp(name, "md5") == 0) {
|
||||||
|
*type_out = CLI_HASH_MD5;
|
||||||
|
} else if (strcasecmp(name, "sha1") == 0) {
|
||||||
|
*type_out = CLI_HASH_SHA1;
|
||||||
|
} else if ((strcasecmp(name, "sha2-256") == 0) || (strcasecmp(name, "sha256") == 0)) {
|
||||||
|
*type_out = CLI_HASH_SHA2_256;
|
||||||
|
} else if ((strcasecmp(name, "sha2-384") == 0) || (strcasecmp(name, "sha384") == 0)) {
|
||||||
|
*type_out = CLI_HASH_SHA2_384;
|
||||||
|
} else if ((strcasecmp(name, "sha2-512") == 0) || (strcasecmp(name, "sha512") == 0)) {
|
||||||
|
*type_out = CLI_HASH_SHA2_512;
|
||||||
|
} else {
|
||||||
|
return CL_EARG; // Unknown hash type name
|
||||||
|
}
|
||||||
|
|
||||||
|
return CL_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
cl_error_t hm_addhash_str(struct cl_engine *engine, hash_purpose_t purpose, const char *strhash, uint32_t size, const char *virusname)
|
||||||
{
|
{
|
||||||
cli_hash_type_t type;
|
cli_hash_type_t type;
|
||||||
char binhash[CLI_HASHLEN_MAX];
|
char binhash[SHA256_HASH_SIZE];
|
||||||
int hlen;
|
size_t hlen;
|
||||||
|
|
||||||
if (!root || !strhash) {
|
if (!engine || !strhash) {
|
||||||
cli_errmsg("hm_addhash_str: NULL root or hash\n");
|
cli_errmsg("hm_addhash_str: NULL engine or hash\n");
|
||||||
return CL_ENULLARG;
|
return CL_ENULLARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,46 +140,78 @@ int hm_addhash_str(struct cli_matcher *root, const char *strhash, uint32_t size,
|
||||||
|
|
||||||
hlen = strlen(strhash);
|
hlen = strlen(strhash);
|
||||||
switch (hlen) {
|
switch (hlen) {
|
||||||
case 32:
|
case (MD5_HASH_SIZE * 2):
|
||||||
type = CLI_HASH_MD5;
|
type = CLI_HASH_MD5;
|
||||||
break;
|
break;
|
||||||
case 40:
|
case (SHA1_HASH_SIZE * 2):
|
||||||
type = CLI_HASH_SHA1;
|
type = CLI_HASH_SHA1;
|
||||||
break;
|
break;
|
||||||
case 64:
|
case (SHA256_HASH_SIZE * 2):
|
||||||
type = CLI_HASH_SHA256;
|
type = CLI_HASH_SHA2_256;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
cli_errmsg("hm_addhash_str: invalid hash %s -- FIXME!\n", strhash);
|
cli_errmsg("hm_addhash_str: invalid hash %s -- FIXME!\n", strhash);
|
||||||
return CL_EARG;
|
return CL_EARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cli_hex2str_to(strhash, (char *)binhash, hlen)) {
|
if (cli_hex2str_to(strhash, (char *)binhash, hlen)) {
|
||||||
cli_errmsg("hm_addhash_str: invalid hash %s\n", strhash);
|
cli_errmsg("hm_addhash_str: invalid hash %s\n", strhash);
|
||||||
return CL_EARG;
|
return CL_EARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
return hm_addhash_bin(root, binhash, type, size, virusname);
|
return hm_addhash_bin(engine, purpose, binhash, type, size, virusname);
|
||||||
}
|
}
|
||||||
|
|
||||||
const unsigned int hashlen[] = {
|
cl_error_t hm_addhash_bin(struct cl_engine *engine, hash_purpose_t purpose, const void *binhash, cli_hash_type_t type, uint32_t size, const char *virusname)
|
||||||
CLI_HASHLEN_MD5,
|
|
||||||
CLI_HASHLEN_SHA1,
|
|
||||||
CLI_HASHLEN_SHA256};
|
|
||||||
|
|
||||||
int hm_addhash_bin(struct cli_matcher *root, const void *binhash, cli_hash_type_t type, uint32_t size, const char *virusname)
|
|
||||||
{
|
{
|
||||||
const unsigned int hlen = hashlen[type];
|
size_t hlen = cli_hash_len(type);
|
||||||
const struct cli_htu32_element *item;
|
const struct cli_htu32_element *item;
|
||||||
struct cli_sz_hash *szh;
|
struct cli_sz_hash *szh;
|
||||||
struct cli_htu32 *ht;
|
struct cli_htu32 *ht;
|
||||||
int i;
|
cl_error_t ret;
|
||||||
|
struct cli_matcher *root = NULL;
|
||||||
|
|
||||||
|
if (purpose == HASH_PURPOSE_PE_SECTION_DETECT) {
|
||||||
|
root = engine->hm_mdb;
|
||||||
|
} else if (purpose == HASH_PURPOSE_WHOLE_FILE_DETECT) {
|
||||||
|
root = engine->hm_hdb;
|
||||||
|
} else if (purpose == HASH_PURPOSE_PE_IMPORT_DETECT) {
|
||||||
|
root = engine->hm_imp;
|
||||||
|
} else if (purpose == HASH_PURPOSE_WHOLE_FILE_FP_CHECK) {
|
||||||
|
if ((type == CLI_HASH_MD5 || type == CLI_HASH_SHA1) &&
|
||||||
|
(engine->engine_options & ENGINE_OPTIONS_FIPS_LIMITS)) {
|
||||||
|
return CL_SUCCESS; // No error, just skip adding MD5/SHA1 FP hashes in FIPS mode
|
||||||
|
}
|
||||||
|
root = engine->hm_fp;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NULL == root) {
|
||||||
|
if (NULL == (root = MPOOL_CALLOC(engine->mempool, 1, sizeof(*root)))) {
|
||||||
|
return CL_EMEM;
|
||||||
|
}
|
||||||
|
#ifdef USE_MPOOL
|
||||||
|
root->mempool = engine->mempool;
|
||||||
|
#endif
|
||||||
|
if (purpose == HASH_PURPOSE_WHOLE_FILE_DETECT) {
|
||||||
|
engine->hm_hdb = root;
|
||||||
|
} else if (purpose == HASH_PURPOSE_PE_SECTION_DETECT) {
|
||||||
|
engine->hm_mdb = root;
|
||||||
|
} else if (purpose == HASH_PURPOSE_PE_IMPORT_DETECT) {
|
||||||
|
engine->hm_imp = root;
|
||||||
|
} else if (purpose == HASH_PURPOSE_WHOLE_FILE_FP_CHECK) {
|
||||||
|
engine->hm_fp = root;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (size) {
|
if (size) {
|
||||||
/* size non-zero, find sz_hash element in size-driven hashtable */
|
/* size non-zero, find sz_hash element in size-driven hashtable */
|
||||||
ht = &root->hm.sizehashes[type];
|
ht = &root->hm.sizehashes[type];
|
||||||
if (!root->hm.sizehashes[type].capacity) {
|
if (!root->hm.sizehashes[type].capacity) {
|
||||||
i = CLI_HTU32_INIT(ht, 64, root->mempool);
|
ret = CLI_HTU32_INIT(ht, 64, root->mempool);
|
||||||
if (i) return i;
|
if (CL_SUCCESS != ret) {
|
||||||
|
cli_errmsg("hm_addhash_bin: failed to initialize hash table\n");
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
item = cli_htu32_find(ht, size);
|
item = cli_htu32_find(ht, size);
|
||||||
|
@ -98,14 +225,15 @@ int hm_addhash_bin(struct cli_matcher *root, const void *binhash, cli_hash_type_
|
||||||
|
|
||||||
htitem.key = size;
|
htitem.key = size;
|
||||||
htitem.data.as_ptr = szh;
|
htitem.data.as_ptr = szh;
|
||||||
i = CLI_HTU32_INSERT(ht, &htitem, root->mempool);
|
ret = CLI_HTU32_INSERT(ht, &htitem, root->mempool);
|
||||||
if (i) {
|
if (CL_SUCCESS != ret) {
|
||||||
cli_errmsg("hm_addhash_bin: failed to add item to hashtab");
|
cli_errmsg("hm_addhash_bin: failed to add item to hashtab");
|
||||||
MPOOL_FREE(root->mempool, szh);
|
MPOOL_FREE(root->mempool, szh);
|
||||||
return i;
|
return ret;
|
||||||
}
|
}
|
||||||
} else
|
} else {
|
||||||
szh = (struct cli_sz_hash *)item->data.as_ptr;
|
szh = (struct cli_sz_hash *)item->data.as_ptr;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
/* size 0 = wildcard */
|
/* size 0 = wildcard */
|
||||||
szh = &root->hwild.hashes[type];
|
szh = &root->hwild.hashes[type];
|
||||||
|
@ -133,7 +261,7 @@ int hm_addhash_bin(struct cli_matcher *root, const void *binhash, cli_hash_type_
|
||||||
memcpy(&szh->hash_array[(szh->items - 1) * hlen], binhash, hlen);
|
memcpy(&szh->hash_array[(szh->items - 1) * hlen], binhash, hlen);
|
||||||
szh->virusnames[(szh->items - 1)] = virusname;
|
szh->virusnames[(szh->items - 1)] = virusname;
|
||||||
|
|
||||||
return 0;
|
return CL_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int hm_cmp(const uint8_t *itm, const uint8_t *ref, unsigned int keylen)
|
static inline int hm_cmp(const uint8_t *itm, const uint8_t *ref, unsigned int keylen)
|
||||||
|
@ -209,7 +337,7 @@ void hm_flush(struct cli_matcher *root)
|
||||||
|
|
||||||
while ((item = cli_htu32_next(ht, item))) {
|
while ((item = cli_htu32_next(ht, item))) {
|
||||||
szh = (struct cli_sz_hash *)item->data.as_ptr;
|
szh = (struct cli_sz_hash *)item->data.as_ptr;
|
||||||
keylen = hashlen[type];
|
keylen = cli_hash_len(type);
|
||||||
|
|
||||||
if (szh->items > 1)
|
if (szh->items > 1)
|
||||||
hm_sort(szh, 0, szh->items, keylen);
|
hm_sort(szh, 0, szh->items, keylen);
|
||||||
|
@ -218,29 +346,29 @@ void hm_flush(struct cli_matcher *root)
|
||||||
|
|
||||||
for (type = CLI_HASH_MD5; type < CLI_HASH_AVAIL_TYPES; type++) {
|
for (type = CLI_HASH_MD5; type < CLI_HASH_AVAIL_TYPES; type++) {
|
||||||
szh = &root->hwild.hashes[type];
|
szh = &root->hwild.hashes[type];
|
||||||
keylen = hashlen[type];
|
keylen = cli_hash_len(type);
|
||||||
|
|
||||||
if (szh->items > 1)
|
if (szh->items > 1)
|
||||||
hm_sort(szh, 0, szh->items, keylen);
|
hm_sort(szh, 0, szh->items, keylen);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int cli_hm_have_size(const struct cli_matcher *root, cli_hash_type_t type, uint32_t size)
|
bool cli_hm_have_size(const struct cli_matcher *root, cli_hash_type_t type, uint32_t size)
|
||||||
{
|
{
|
||||||
return (size && size != 0xffffffff && root && root->hm.sizehashes[type].capacity && cli_htu32_find(&root->hm.sizehashes[type], size));
|
return (size && size != 0xffffffff && root && root->hm.sizehashes[type].capacity && cli_htu32_find(&root->hm.sizehashes[type], size));
|
||||||
}
|
}
|
||||||
|
|
||||||
int cli_hm_have_wild(const struct cli_matcher *root, cli_hash_type_t type)
|
bool cli_hm_have_wild(const struct cli_matcher *root, cli_hash_type_t type)
|
||||||
{
|
{
|
||||||
return (root && root->hwild.hashes[type].items);
|
return (root && root->hwild.hashes[type].items);
|
||||||
}
|
}
|
||||||
|
|
||||||
int cli_hm_have_any(const struct cli_matcher *root, cli_hash_type_t type)
|
bool cli_hm_have_any(const struct cli_matcher *root, cli_hash_type_t type)
|
||||||
{
|
{
|
||||||
return (root && (root->hwild.hashes[type].items || root->hm.sizehashes[type].capacity));
|
return (root && (root->hwild.hashes[type].items || root->hm.sizehashes[type].capacity));
|
||||||
}
|
}
|
||||||
|
|
||||||
static int hm_scan(const unsigned char *digest, const char **virname, const struct cli_sz_hash *szh, cli_hash_type_t type)
|
static cl_error_t hm_scan(const uint8_t *digest, const char **virname, const struct cli_sz_hash *szh, cli_hash_type_t type)
|
||||||
{
|
{
|
||||||
unsigned int keylen;
|
unsigned int keylen;
|
||||||
size_t l, r;
|
size_t l, r;
|
||||||
|
@ -248,7 +376,7 @@ static int hm_scan(const unsigned char *digest, const char **virname, const stru
|
||||||
if (!digest || !szh || !szh->items)
|
if (!digest || !szh || !szh->items)
|
||||||
return CL_CLEAN;
|
return CL_CLEAN;
|
||||||
|
|
||||||
keylen = hashlen[type];
|
keylen = cli_hash_len(type);
|
||||||
|
|
||||||
l = 0;
|
l = 0;
|
||||||
r = szh->items - 1;
|
r = szh->items - 1;
|
||||||
|
@ -272,7 +400,7 @@ static int hm_scan(const unsigned char *digest, const char **virname, const stru
|
||||||
}
|
}
|
||||||
|
|
||||||
/* cli_hm_scan will scan only size-specific hashes, if any */
|
/* cli_hm_scan will scan only size-specific hashes, if any */
|
||||||
int cli_hm_scan(const unsigned char *digest, uint32_t size, const char **virname, const struct cli_matcher *root, cli_hash_type_t type)
|
cl_error_t cli_hm_scan(const uint8_t *digest, uint32_t size, const char **virname, const struct cli_matcher *root, cli_hash_type_t type)
|
||||||
{
|
{
|
||||||
const struct cli_htu32_element *item;
|
const struct cli_htu32_element *item;
|
||||||
struct cli_sz_hash *szh;
|
struct cli_sz_hash *szh;
|
||||||
|
@ -290,7 +418,7 @@ int cli_hm_scan(const unsigned char *digest, uint32_t size, const char **virname
|
||||||
}
|
}
|
||||||
|
|
||||||
/* cli_hm_scan_wild will scan only size-agnostic hashes, if any */
|
/* cli_hm_scan_wild will scan only size-agnostic hashes, if any */
|
||||||
int cli_hm_scan_wild(const unsigned char *digest, const char **virname, const struct cli_matcher *root, cli_hash_type_t type)
|
cl_error_t cli_hm_scan_wild(const uint8_t *digest, const char **virname, const struct cli_matcher *root, cli_hash_type_t type)
|
||||||
{
|
{
|
||||||
if (!digest || !root || !root->hwild.hashes[type].items)
|
if (!digest || !root || !root->hwild.hashes[type].items)
|
||||||
return CL_CLEAN;
|
return CL_CLEAN;
|
||||||
|
|
|
@ -30,6 +30,13 @@
|
||||||
#include "matcher-hash-types.h"
|
#include "matcher-hash-types.h"
|
||||||
#include "hashtab.h"
|
#include "hashtab.h"
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
HASH_PURPOSE_PE_SECTION_DETECT = 0, /** PE section hash malware detection (aka .mdb, .mdu, .msb, .msu) */
|
||||||
|
HASH_PURPOSE_WHOLE_FILE_DETECT, /** Whole file hash malware detection (aka .hdb, .hdu, .hsb, .hsu) */
|
||||||
|
HASH_PURPOSE_WHOLE_FILE_FP_CHECK, /** Whole file false positive prevention (aka .fp, .sfp) */
|
||||||
|
HASH_PURPOSE_PE_IMPORT_DETECT /** PE import hash malware detection (aka .imp) */
|
||||||
|
} hash_purpose_t;
|
||||||
|
|
||||||
struct cli_sz_hash {
|
struct cli_sz_hash {
|
||||||
uint8_t *hash_array;
|
uint8_t *hash_array;
|
||||||
const char **virusnames;
|
const char **virusnames;
|
||||||
|
@ -44,14 +51,14 @@ struct cli_hash_wild {
|
||||||
struct cli_sz_hash hashes[CLI_HASH_AVAIL_TYPES];
|
struct cli_sz_hash hashes[CLI_HASH_AVAIL_TYPES];
|
||||||
};
|
};
|
||||||
|
|
||||||
int hm_addhash_str(struct cli_matcher *root, const char *strhash, uint32_t size, const char *virusname);
|
cl_error_t hm_addhash_str(struct cl_engine *engine, hash_purpose_t purpose, const char *strhash, uint32_t size, const char *virusname);
|
||||||
int hm_addhash_bin(struct cli_matcher *root, const void *binhash, cli_hash_type_t type, uint32_t size, const char *virusname);
|
cl_error_t hm_addhash_bin(struct cl_engine *engine, hash_purpose_t purpose, const void *binhash, cli_hash_type_t type, uint32_t size, const char *virusname);
|
||||||
void hm_flush(struct cli_matcher *root);
|
void hm_flush(struct cli_matcher *root);
|
||||||
int cli_hm_scan(const unsigned char *digest, uint32_t size, const char **virname, const struct cli_matcher *root, cli_hash_type_t type);
|
cl_error_t cli_hm_scan(const uint8_t *digest, uint32_t size, const char **virname, const struct cli_matcher *root, cli_hash_type_t type);
|
||||||
int cli_hm_scan_wild(const unsigned char *digest, const char **virname, const struct cli_matcher *root, cli_hash_type_t type);
|
cl_error_t cli_hm_scan_wild(const uint8_t *digest, const char **virname, const struct cli_matcher *root, cli_hash_type_t type);
|
||||||
int cli_hm_have_size(const struct cli_matcher *root, cli_hash_type_t type, uint32_t size);
|
bool cli_hm_have_size(const struct cli_matcher *root, cli_hash_type_t type, uint32_t size);
|
||||||
int cli_hm_have_wild(const struct cli_matcher *root, cli_hash_type_t type);
|
bool cli_hm_have_wild(const struct cli_matcher *root, cli_hash_type_t type);
|
||||||
int cli_hm_have_any(const struct cli_matcher *root, cli_hash_type_t type);
|
bool cli_hm_have_any(const struct cli_matcher *root, cli_hash_type_t type);
|
||||||
void hm_free(struct cli_matcher *root);
|
void hm_free(struct cli_matcher *root);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -572,148 +572,178 @@ void cli_targetinfo_destroy(struct cli_target_info *info)
|
||||||
cl_error_t cli_check_fp(cli_ctx *ctx, const char *vname)
|
cl_error_t cli_check_fp(cli_ctx *ctx, const char *vname)
|
||||||
{
|
{
|
||||||
cl_error_t status = CL_VIRUS;
|
cl_error_t status = CL_VIRUS;
|
||||||
char md5[33];
|
cl_error_t ret;
|
||||||
unsigned int i;
|
|
||||||
|
size_t i;
|
||||||
const char *virname = NULL;
|
const char *virname = NULL;
|
||||||
fmap_t *map;
|
fmap_t *map;
|
||||||
int32_t stack_index;
|
int32_t stack_index;
|
||||||
const char *ptr;
|
|
||||||
uint8_t shash1[SHA1_HASH_SIZE * 2 + 1];
|
uint8_t *hash;
|
||||||
uint8_t shash256[SHA256_HASH_SIZE * 2 + 1];
|
cli_hash_type_t hash_type;
|
||||||
int have_sha1, have_sha256;
|
char hash_string[SHA256_HASH_SIZE * 2 + 1];
|
||||||
unsigned char *digest;
|
|
||||||
size_t size;
|
bool need_hash[CLI_HASH_AVAIL_TYPES] = {false};
|
||||||
|
|
||||||
stack_index = (int32_t)ctx->recursion_level;
|
stack_index = (int32_t)ctx->recursion_level;
|
||||||
|
|
||||||
|
char *source = NULL;
|
||||||
|
size_t source_len;
|
||||||
|
|
||||||
while (stack_index >= 0) {
|
while (stack_index >= 0) {
|
||||||
map = ctx->recursion_stack[stack_index].fmap;
|
map = ctx->recursion_stack[stack_index].fmap;
|
||||||
|
|
||||||
if (CL_SUCCESS != fmap_get_hash(map, &digest, CLI_HASH_MD5)) {
|
need_hash[CLI_HASH_MD5] = cli_hm_have_size(ctx->engine->hm_fp, CLI_HASH_MD5, map->len) ||
|
||||||
cli_dbgmsg("cli_check_fp: Failed to get a hash for the map at stack index # %u\n", stack_index);
|
cli_hm_have_wild(ctx->engine->hm_fp, CLI_HASH_MD5);
|
||||||
stack_index--;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
size = map->len;
|
|
||||||
|
|
||||||
/*
|
need_hash[CLI_HASH_SHA1] = cli_hm_have_size(ctx->engine->hm_fp, CLI_HASH_SHA1, map->len) ||
|
||||||
* First, check the MD5 digest.
|
cli_hm_have_wild(ctx->engine->hm_fp, CLI_HASH_SHA1) ||
|
||||||
* MD5 is default, so it always exists.
|
cli_hm_have_size(ctx->engine->hm_fp, CLI_HASH_SHA1, 1);
|
||||||
*/
|
|
||||||
if (cli_hm_scan(digest, size, &virname, ctx->engine->hm_fp, CLI_HASH_MD5) == CL_VIRUS) {
|
|
||||||
cli_dbgmsg("cli_check_fp(md5): Found false positive detection (fp sig: %s), size: %d\n", virname, (int)size);
|
|
||||||
return CL_CLEAN;
|
|
||||||
} else if (cli_hm_scan_wild(digest, &virname, ctx->engine->hm_fp, CLI_HASH_MD5) == CL_VIRUS) {
|
|
||||||
cli_dbgmsg("cli_check_fp(md5): Found false positive detection (fp sig: %s), size: *\n", virname);
|
|
||||||
return CL_CLEAN;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cli_debug_flag || ctx->engine->cb_hash) {
|
need_hash[CLI_HASH_SHA2_256] = cli_hm_have_size(ctx->engine->hm_fp, CLI_HASH_SHA2_256, map->len) ||
|
||||||
const char *name = ctx->recursion_stack[stack_index].fmap->name;
|
cli_hm_have_wild(ctx->engine->hm_fp, CLI_HASH_SHA2_256) ||
|
||||||
const char *type = cli_ftname(ctx->recursion_stack[stack_index].type);
|
cli_hm_have_size(ctx->engine->hm_fp, CLI_HASH_SHA2_256, 1) ||
|
||||||
|
// If debug logging is enabled, we want to calculate SHA256 hashes for all layers.
|
||||||
|
// Some users rely on the debug log output to create new FP signatures.
|
||||||
|
cli_debug_flag;
|
||||||
|
|
||||||
for (i = 0; i < 16; i++)
|
/* Set fmap to need hash later if required.
|
||||||
sprintf(md5 + i * 2, "%02x", digest[i]);
|
* This is an optimization so we can calculate all needed hashes in one pass. */
|
||||||
md5[32] = 0;
|
for (hash_type = CLI_HASH_MD5; hash_type < CLI_HASH_AVAIL_TYPES; hash_type++) {
|
||||||
|
if (need_hash[hash_type]) {
|
||||||
cli_dbgmsg("FP SIGNATURE: %s:%u:%s # Name: %s, Type: %s\n",
|
ret = fmap_will_need_hash_later(map, hash_type);
|
||||||
md5, (unsigned int)size, vname ? vname : "Name", name ? name : "n/a", type);
|
if (CL_SUCCESS != ret) {
|
||||||
}
|
cli_dbgmsg("cli_check_fp: Failed to set fmap to need MD5 hash later\n");
|
||||||
|
status = CL_VIRUS;
|
||||||
have_sha1 = cli_hm_have_size(ctx->engine->hm_fp, CLI_HASH_SHA1, size) || cli_hm_have_wild(ctx->engine->hm_fp, CLI_HASH_SHA1) || cli_hm_have_size(ctx->engine->hm_fp, CLI_HASH_SHA1, 1);
|
goto done;
|
||||||
have_sha256 = cli_hm_have_size(ctx->engine->hm_fp, CLI_HASH_SHA256, size) || cli_hm_have_wild(ctx->engine->hm_fp, CLI_HASH_SHA256);
|
|
||||||
if (have_sha1 || have_sha256) {
|
|
||||||
if ((ptr = fmap_need_off_once(map, 0, size))) {
|
|
||||||
if (have_sha1) {
|
|
||||||
cl_sha1(ptr, size, &shash1[SHA1_HASH_SIZE], NULL);
|
|
||||||
|
|
||||||
if (cli_hm_scan(&shash1[SHA1_HASH_SIZE], size, &virname, ctx->engine->hm_fp, CLI_HASH_SHA1) == CL_VIRUS) {
|
|
||||||
cli_dbgmsg("cli_check_fp(sha1): Found false positive detection (fp sig: %s)\n", virname);
|
|
||||||
return CL_CLEAN;
|
|
||||||
}
|
|
||||||
if (cli_hm_scan_wild(&shash1[SHA1_HASH_SIZE], &virname, ctx->engine->hm_fp, CLI_HASH_SHA1) == CL_VIRUS) {
|
|
||||||
cli_dbgmsg("cli_check_fp(sha1): Found false positive detection (fp sig: %s)\n", virname);
|
|
||||||
return CL_CLEAN;
|
|
||||||
}
|
|
||||||
/* See whether the hash matches those loaded in from .cat files
|
|
||||||
* (associated with the .CAB file type) */
|
|
||||||
if (cli_hm_scan(&shash1[SHA1_HASH_SIZE], 1, &virname, ctx->engine->hm_fp, CLI_HASH_SHA1) == CL_VIRUS) {
|
|
||||||
cli_dbgmsg("cli_check_fp(sha1): Found .CAB false positive detection via catalog file\n");
|
|
||||||
return CL_CLEAN;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (have_sha256) {
|
|
||||||
cl_sha256(ptr, size, &shash256[SHA256_HASH_SIZE], NULL);
|
|
||||||
|
|
||||||
if (cli_hm_scan(&shash256[SHA256_HASH_SIZE], size, &virname, ctx->engine->hm_fp, CLI_HASH_SHA256) == CL_VIRUS) {
|
|
||||||
cli_dbgmsg("cli_check_fp(sha256): Found false positive detection (fp sig: %s)\n", virname);
|
|
||||||
return CL_CLEAN;
|
|
||||||
}
|
|
||||||
if (cli_hm_scan_wild(&shash256[SHA256_HASH_SIZE], &virname, ctx->engine->hm_fp, CLI_HASH_SHA256) == CL_VIRUS) {
|
|
||||||
cli_dbgmsg("cli_check_fp(sha256): Found false positive detection (fp sig: %s)\n", virname);
|
|
||||||
return CL_CLEAN;
|
|
||||||
}
|
|
||||||
/* See whether the hash matches those loaded in from .cat files
|
|
||||||
* (associated with the .CAB file type) */
|
|
||||||
if (cli_hm_scan(&shash256[SHA256_HASH_SIZE], 1, &virname, ctx->engine->hm_fp, CLI_HASH_SHA256) == CL_VIRUS) {
|
|
||||||
cli_dbgmsg("cli_check_fp(sha256): Found .CAB false positive detection via catalog file\n");
|
|
||||||
return CL_CLEAN;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE__INTERNAL__SHA_COLLECT
|
for (hash_type = CLI_HASH_MD5; hash_type < CLI_HASH_AVAIL_TYPES; hash_type++) {
|
||||||
if (SCAN_DEV_COLLECT_SHA && (ctx->sha_collect > 0)) {
|
if (need_hash[hash_type]) {
|
||||||
if ((ptr = fmap_need_off_once(map, 0, size))) {
|
size_t hash_len = cli_hash_len(hash_type);
|
||||||
if (!have_sha256)
|
|
||||||
cl_sha256(ptr, size, shash256 + SHA256_HASH_SIZE, NULL);
|
|
||||||
|
|
||||||
for (i = 0; i < SHA256_HASH_SIZE; i++)
|
/* If we need a hash, we will calculate it now */
|
||||||
sprintf((char *)shash256 + i * 2, "%02x", shash256[SHA256_HASH_SIZE + i]);
|
ret = fmap_get_hash(map, &hash, hash_type);
|
||||||
|
if (CL_SUCCESS != ret) {
|
||||||
if (!have_sha1)
|
cli_dbgmsg("cli_check_fp: Failed to get hash for the map at stack index # %u\n", stack_index);
|
||||||
cl_sha1(ptr, size, shash1 + SHA1_HASH_SIZE);
|
status = CL_VIRUS;
|
||||||
|
goto done;
|
||||||
for (i = 0; i < SHA1_HASH_SIZE; i++)
|
|
||||||
sprintf((char *)shash1 + i * 2, "%02x", shash1[SHA1_HASH_SIZE + i]);
|
|
||||||
|
|
||||||
if (NULL == ctx->target_filepath) {
|
|
||||||
cli_errmsg("COLLECT:%s:%s:%u:%s:%s\n", shash256, shash1, size, vname ? vname : "noname", "NO_IDEA");
|
|
||||||
} else {
|
|
||||||
cli_errmsg("COLLECT:%s:%s:%u:%s:%s\n", shash256, shash1, size, vname ? vname : "noname", ctx->target_filepath);
|
|
||||||
}
|
}
|
||||||
} else
|
|
||||||
cli_errmsg("can't compute sha\n!");
|
|
||||||
|
|
||||||
ctx->sha_collect = -1;
|
if (cli_debug_flag ||
|
||||||
}
|
((CLI_HASH_MD5 == hash_type) && (ctx->engine->cb_hash))) {
|
||||||
#endif
|
/* Convert hash to string */
|
||||||
|
for (i = 0; i < hash_len; i++) {
|
||||||
|
sprintf(hash_string + i * 2, "%02x", hash[i]);
|
||||||
|
}
|
||||||
|
hash_string[hash_len * 2] = 0;
|
||||||
|
|
||||||
if (ctx->engine->cb_hash)
|
const char *name = ctx->recursion_stack[stack_index].fmap->name;
|
||||||
ctx->engine->cb_hash(fmap_fd(ctx->fmap), size, (const unsigned char *)md5, vname ? vname : "noname", ctx->cb_ctx);
|
const char *type = cli_ftname(ctx->recursion_stack[stack_index].type);
|
||||||
|
|
||||||
if (ctx->engine->cb_stats_add_sample) {
|
cli_dbgmsg("FP SIGNATURE: %s:%u:%s # Name: %s, Type: %s\n",
|
||||||
stats_section_t sections;
|
hash_string, (unsigned int)map->len, vname ? vname : "Name", name ? name : "n/a", type);
|
||||||
memset(§ions, 0x00, sizeof(stats_section_t));
|
}
|
||||||
|
|
||||||
if (!(ctx->engine->engine_options & ENGINE_OPTIONS_DISABLE_PE_STATS) &&
|
if (CLI_HASH_MD5 == hash_type) {
|
||||||
!(ctx->engine->dconf->stats & (DCONF_STATS_DISABLED | DCONF_STATS_PE_SECTION_DISABLED)))
|
/* Run legacy callbacks that include MD5 hash */
|
||||||
cli_genhash_pe(ctx, CL_GENHASH_PE_CLASS_SECTION, 1, §ions);
|
if (ctx->engine->cb_hash) {
|
||||||
|
ctx->engine->cb_hash(fmap_fd(ctx->fmap), map->len, hash_string, vname ? vname : "noname", ctx->cb_ctx);
|
||||||
|
}
|
||||||
|
|
||||||
// TODO We probably only want to call cb_stats_add_sample when
|
if (ctx->engine->cb_stats_add_sample) {
|
||||||
// sections.section != NULL... leaving as is for now
|
stats_section_t sections;
|
||||||
ctx->engine->cb_stats_add_sample(vname ? vname : "noname", digest, size, §ions, ctx->engine->stats_data);
|
memset(§ions, 0x00, sizeof(stats_section_t));
|
||||||
|
|
||||||
if (sections.sections) {
|
if (!(ctx->engine->engine_options & ENGINE_OPTIONS_DISABLE_PE_STATS) &&
|
||||||
free(sections.sections);
|
!(ctx->engine->dconf->stats & (DCONF_STATS_DISABLED | DCONF_STATS_PE_SECTION_DISABLED))) {
|
||||||
|
|
||||||
|
cli_genhash_pe(ctx, CL_GENHASH_PE_CLASS_SECTION, 1, §ions);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO We probably only want to call cb_stats_add_sample when
|
||||||
|
// sections.section != NULL... leaving as is for now
|
||||||
|
ctx->engine->cb_stats_add_sample(vname ? vname : "noname", hash, map->len, §ions, ctx->engine->stats_data);
|
||||||
|
|
||||||
|
if (sections.sections) {
|
||||||
|
free(sections.sections);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cli_hm_scan(hash, map->len, &virname, ctx->engine->hm_fp, hash_type) == CL_VIRUS) {
|
||||||
|
cli_dbgmsg("cli_check_fp: Found false positive detection for %s (fp sig: %s)\n", cli_hash_name(hash_type), virname);
|
||||||
|
|
||||||
|
source_len = strlen(virname) + strlen("false positive signature match: ") + 1;
|
||||||
|
source = malloc(source_len);
|
||||||
|
if (source) {
|
||||||
|
snprintf(source, source_len, "false positive signature match: %s", virname);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove any evidence and set the verdict to trusted for the layer where the FP hash matched, and for all contained layers.
|
||||||
|
(void)cli_trust_layers(ctx, (uint32_t)stack_index, ctx->recursion_level, source);
|
||||||
|
|
||||||
|
free(source);
|
||||||
|
source = NULL;
|
||||||
|
|
||||||
|
status = CL_VERIFIED;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
if (cli_hm_scan_wild(hash, &virname, ctx->engine->hm_fp, hash_type) == CL_VIRUS) {
|
||||||
|
cli_dbgmsg("cli_check_fp: Found false positive detection for %s (fp sig: %s)\n", cli_hash_name(hash_type), virname);
|
||||||
|
|
||||||
|
source_len = strlen(virname) + strlen("false positive signature match: ") + 1;
|
||||||
|
source = malloc(source_len);
|
||||||
|
if (source) {
|
||||||
|
snprintf(source, source_len, "false positive signature match: %s", virname);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove any evidence and set the verdict to trusted for the layer where the FP hash matched, and for all contained layers.
|
||||||
|
(void)cli_trust_layers(ctx, (uint32_t)stack_index, ctx->recursion_level, source);
|
||||||
|
|
||||||
|
free(source);
|
||||||
|
source = NULL;
|
||||||
|
|
||||||
|
status = CL_VERIFIED;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CLI_HASH_MD5 != hash_type) {
|
||||||
|
/* See whether the hash matches those loaded in from .cat files
|
||||||
|
* (associated with the .CAB file type) */
|
||||||
|
if (cli_hm_scan(hash, 1, &virname, ctx->engine->hm_fp, hash_type) == CL_VIRUS) {
|
||||||
|
cli_dbgmsg("cli_check_fp: Found .CAB false positive detection for %s via catalog file\n", cli_hash_name(hash_type));
|
||||||
|
|
||||||
|
source_len = strlen(virname) + strlen("false positive signature match: ") + 1;
|
||||||
|
source = malloc(source_len);
|
||||||
|
if (source) {
|
||||||
|
snprintf(source, source_len, "false positive signature match: %s", virname);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove any evidence and set the verdict to trusted for the layer where the FP hash matched, and for all contained layers.
|
||||||
|
(void)cli_trust_layers(ctx, (uint32_t)stack_index, ctx->recursion_level, source);
|
||||||
|
|
||||||
|
free(source);
|
||||||
|
source = NULL;
|
||||||
|
|
||||||
|
status = CL_VERIFIED;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
stack_index -= 1;
|
stack_index -= 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
|
||||||
|
if (NULL != source) {
|
||||||
|
free(source);
|
||||||
|
}
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -778,13 +808,13 @@ int32_t cli_bcapi_matchicon(struct cli_bc_ctx *ctx, const uint8_t *grp1, int32_t
|
||||||
return (int32_t)ret;
|
return (int32_t)ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
cl_error_t cli_scan_desc(int desc, cli_ctx *ctx, cli_file_t ftype, bool filetype_only, struct cli_matched_type **ftoffset, unsigned int acmode, struct cli_ac_result **acres, const char *name, uint32_t attributes)
|
cl_error_t cli_scan_desc(int desc, cli_ctx *ctx, cli_file_t ftype, bool filetype_only, struct cli_matched_type **ftoffset, unsigned int acmode, struct cli_ac_result **acres, const char *name, const char *path, uint32_t attributes)
|
||||||
{
|
{
|
||||||
cl_error_t status = CL_CLEAN;
|
cl_error_t status = CL_CLEAN;
|
||||||
int empty;
|
int empty;
|
||||||
fmap_t *new_map = NULL;
|
fmap_t *new_map = NULL;
|
||||||
|
|
||||||
new_map = fmap_check_empty(desc, 0, 0, &empty, name);
|
new_map = fmap_check_empty(desc, 0, 0, &empty, name, path);
|
||||||
if (NULL == new_map) {
|
if (NULL == new_map) {
|
||||||
if (!empty) {
|
if (!empty) {
|
||||||
cli_dbgmsg("cli_scan_desc: Failed to allocate new map for file descriptor scan.\n");
|
cli_dbgmsg("cli_scan_desc: Failed to allocate new map for file descriptor scan.\n");
|
||||||
|
@ -799,13 +829,13 @@ cl_error_t cli_scan_desc(int desc, cli_ctx *ctx, cli_file_t ftype, bool filetype
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
status = cli_scan_fmap(ctx, ftype, filetype_only, ftoffset, acmode, acres, NULL);
|
status = cli_scan_fmap(ctx, ftype, filetype_only, ftoffset, acmode, acres);
|
||||||
|
|
||||||
(void)cli_recursion_stack_pop(ctx); /* Restore the parent fmap */
|
(void)cli_recursion_stack_pop(ctx); /* Restore the parent fmap */
|
||||||
|
|
||||||
done:
|
done:
|
||||||
if (NULL != new_map) {
|
if (NULL != new_map) {
|
||||||
funmap(new_map);
|
fmap_free(new_map);
|
||||||
}
|
}
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
|
@ -830,7 +860,7 @@ static int intermediates_eval(cli_ctx *ctx, struct cli_ac_lsig *ac_lsig)
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static cl_error_t lsig_eval(cli_ctx *ctx, struct cli_matcher *root, struct cli_ac_data *acdata, struct cli_target_info *target_info, const char *hash, uint32_t lsid)
|
static cl_error_t lsig_eval(cli_ctx *ctx, struct cli_matcher *root, struct cli_ac_data *acdata, struct cli_target_info *target_info, uint32_t lsid)
|
||||||
{
|
{
|
||||||
cl_error_t status = CL_CLEAN;
|
cl_error_t status = CL_CLEAN;
|
||||||
unsigned evalcnt = 0;
|
unsigned evalcnt = 0;
|
||||||
|
@ -893,7 +923,10 @@ static cl_error_t lsig_eval(cli_ctx *ctx, struct cli_matcher *root, struct cli_a
|
||||||
// Instead of alerting, we'll make a duplicate fmap (add recursion depth, to prevent infinite loops) and
|
// Instead of alerting, we'll make a duplicate fmap (add recursion depth, to prevent infinite loops) and
|
||||||
// scan the file with the handler type.
|
// scan the file with the handler type.
|
||||||
|
|
||||||
if (hash && 0 != memcmp(ctx->handlertype_hash, hash, 16)) {
|
/*
|
||||||
|
* If the current layer was re-typed already, then prevent HandlerType from being applied again.
|
||||||
|
*/
|
||||||
|
if (!(ctx->recursion_stack[ctx->recursion_level].attributes & LAYER_ATTRIBUTES_RETYPED)) {
|
||||||
/*
|
/*
|
||||||
* Create an fmap window into our current fmap using the original offset & length, and rescan as the new type
|
* Create an fmap window into our current fmap using the original offset & length, and rescan as the new type
|
||||||
*
|
*
|
||||||
|
@ -910,9 +943,7 @@ static cl_error_t lsig_eval(cli_ctx *ctx, struct cli_matcher *root, struct cli_a
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(ctx->handlertype_hash, hash, 16);
|
status = cli_recursion_stack_push(ctx, new_map, ac_lsig->tdb.handlertype[0], true, LAYER_ATTRIBUTES_RETYPED); /* Perform scan with child fmap */
|
||||||
|
|
||||||
status = cli_recursion_stack_push(ctx, new_map, ac_lsig->tdb.handlertype[0], true, LAYER_ATTRIBUTES_NONE); /* Perform scan with child fmap */
|
|
||||||
if (CL_SUCCESS != status) {
|
if (CL_SUCCESS != status) {
|
||||||
cli_dbgmsg("Failed to re-scan fmap as a new type.\n");
|
cli_dbgmsg("Failed to re-scan fmap as a new type.\n");
|
||||||
goto done;
|
goto done;
|
||||||
|
@ -970,14 +1001,12 @@ done:
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE_YARA
|
#ifdef HAVE_YARA
|
||||||
static cl_error_t yara_eval(cli_ctx *ctx, struct cli_matcher *root, struct cli_ac_data *acdata, struct cli_target_info *target_info, const char *hash, uint32_t lsid)
|
static cl_error_t yara_eval(cli_ctx *ctx, struct cli_matcher *root, struct cli_ac_data *acdata, struct cli_target_info *target_info, uint32_t lsid)
|
||||||
{
|
{
|
||||||
struct cli_ac_lsig *ac_lsig = root->ac_lsigtable[lsid];
|
struct cli_ac_lsig *ac_lsig = root->ac_lsigtable[lsid];
|
||||||
cl_error_t rc;
|
cl_error_t rc;
|
||||||
YR_SCAN_CONTEXT context;
|
YR_SCAN_CONTEXT context;
|
||||||
|
|
||||||
(void)hash;
|
|
||||||
|
|
||||||
memset(&context, 0, sizeof(YR_SCAN_CONTEXT));
|
memset(&context, 0, sizeof(YR_SCAN_CONTEXT));
|
||||||
context.fmap = ctx->fmap;
|
context.fmap = ctx->fmap;
|
||||||
context.file_size = ctx->fmap->len;
|
context.file_size = ctx->fmap->len;
|
||||||
|
@ -999,18 +1028,18 @@ static cl_error_t yara_eval(cli_ctx *ctx, struct cli_matcher *root, struct cli_a
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
cl_error_t cli_exp_eval(cli_ctx *ctx, struct cli_matcher *root, struct cli_ac_data *acdata, struct cli_target_info *target_info, const char *hash)
|
cl_error_t cli_exp_eval(cli_ctx *ctx, struct cli_matcher *root, struct cli_ac_data *acdata, struct cli_target_info *target_info)
|
||||||
{
|
{
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
cl_error_t status = CL_SUCCESS;
|
cl_error_t status = CL_SUCCESS;
|
||||||
|
|
||||||
for (i = 0; i < root->ac_lsigs; i++) {
|
for (i = 0; i < root->ac_lsigs; i++) {
|
||||||
if (root->ac_lsigtable[i]->type == CLI_LSIG_NORMAL) {
|
if (root->ac_lsigtable[i]->type == CLI_LSIG_NORMAL) {
|
||||||
status = lsig_eval(ctx, root, acdata, target_info, hash, i);
|
status = lsig_eval(ctx, root, acdata, target_info, i);
|
||||||
}
|
}
|
||||||
#ifdef HAVE_YARA
|
#ifdef HAVE_YARA
|
||||||
else if (root->ac_lsigtable[i]->type == CLI_YARA_NORMAL || root->ac_lsigtable[i]->type == CLI_YARA_OFFSET) {
|
else if (root->ac_lsigtable[i]->type == CLI_YARA_NORMAL || root->ac_lsigtable[i]->type == CLI_YARA_OFFSET) {
|
||||||
status = yara_eval(ctx, root, acdata, target_info, hash, i);
|
status = yara_eval(ctx, root, acdata, target_info, i);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -1033,11 +1062,16 @@ cl_error_t cli_exp_eval(cli_ctx *ctx, struct cli_matcher *root, struct cli_ac_da
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
cl_error_t cli_scan_fmap(cli_ctx *ctx, cli_file_t ftype, bool filetype_only, struct cli_matched_type **ftoffset, unsigned int acmode, struct cli_ac_result **acres, unsigned char *refhash)
|
cl_error_t cli_scan_fmap(cli_ctx *ctx, cli_file_t ftype, bool filetype_only, struct cli_matched_type **ftoffset, unsigned int acmode, struct cli_ac_result **acres)
|
||||||
{
|
{
|
||||||
const unsigned char *buff;
|
const unsigned char *buff;
|
||||||
cl_error_t ret = CL_CLEAN, type = CL_CLEAN;
|
cl_error_t ret = CL_CLEAN, type = CL_CLEAN;
|
||||||
bool compute_hash[CLI_HASH_AVAIL_TYPES];
|
|
||||||
|
cli_hash_type_t hash_type;
|
||||||
|
bool need_hash[CLI_HASH_AVAIL_TYPES] = {false};
|
||||||
|
void *hashctx[CLI_HASH_AVAIL_TYPES] = {NULL};
|
||||||
|
unsigned char digest[CLI_HASH_AVAIL_TYPES][CLI_HASHLEN_MAX];
|
||||||
|
|
||||||
unsigned int i = 0, j = 0;
|
unsigned int i = 0, j = 0;
|
||||||
uint32_t maxpatlen, bytes, offset = 0;
|
uint32_t maxpatlen, bytes, offset = 0;
|
||||||
|
|
||||||
|
@ -1056,8 +1090,6 @@ cl_error_t cli_scan_fmap(cli_ctx *ctx, cli_file_t ftype, bool filetype_only, str
|
||||||
struct cli_pcre_off target_pcre_offsets_table;
|
struct cli_pcre_off target_pcre_offsets_table;
|
||||||
bool target_pcre_offsets_table_initialized = false;
|
bool target_pcre_offsets_table_initialized = false;
|
||||||
|
|
||||||
unsigned char digest[CLI_HASH_AVAIL_TYPES][CLI_HASHLEN_MAX];
|
|
||||||
|
|
||||||
struct cli_matcher *generic_ac_root = NULL, *target_ac_root = NULL;
|
struct cli_matcher *generic_ac_root = NULL, *target_ac_root = NULL;
|
||||||
|
|
||||||
struct cli_target_info info;
|
struct cli_target_info info;
|
||||||
|
@ -1065,34 +1097,12 @@ cl_error_t cli_scan_fmap(cli_ctx *ctx, cli_file_t ftype, bool filetype_only, str
|
||||||
|
|
||||||
struct cli_matcher *hdb, *fp;
|
struct cli_matcher *hdb, *fp;
|
||||||
|
|
||||||
void *md5ctx = NULL;
|
|
||||||
void *sha1ctx = NULL;
|
|
||||||
void *sha256ctx = NULL;
|
|
||||||
|
|
||||||
if (!ctx->engine) {
|
if (!ctx->engine) {
|
||||||
cli_errmsg("cli_scan_fmap: engine == NULL\n");
|
cli_errmsg("cli_scan_fmap: engine == NULL\n");
|
||||||
ret = CL_ENULLARG;
|
ret = CL_ENULLARG;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
md5ctx = cl_hash_init("md5");
|
|
||||||
if (!(md5ctx)) {
|
|
||||||
ret = CL_EMEM;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
sha1ctx = cl_hash_init("sha1");
|
|
||||||
if (!(sha1ctx)) {
|
|
||||||
ret = CL_EMEM;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
sha256ctx = cl_hash_init("sha256");
|
|
||||||
if (!(sha256ctx)) {
|
|
||||||
ret = CL_EMEM;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!filetype_only) {
|
if (!filetype_only) {
|
||||||
generic_ac_root = ctx->engine->root[0]; /* generic signatures */
|
generic_ac_root = ctx->engine->root[0]; /* generic signatures */
|
||||||
}
|
}
|
||||||
|
@ -1245,36 +1255,35 @@ cl_error_t cli_scan_fmap(cli_ctx *ctx, cli_file_t ftype, bool filetype_only, str
|
||||||
matching with the AC & BM pattern matchers is an optimization so we
|
matching with the AC & BM pattern matchers is an optimization so we
|
||||||
we can do both processes while the cache is still hot. */
|
we can do both processes while the cache is still hot. */
|
||||||
|
|
||||||
if (!refhash) {
|
need_hash[CLI_HASH_MD5] = cli_hm_have_size(hdb, CLI_HASH_MD5, ctx->fmap->len) ||
|
||||||
if (cli_hm_have_size(hdb, CLI_HASH_MD5, ctx->fmap->len) ||
|
cli_hm_have_wild(hdb, CLI_HASH_MD5) ||
|
||||||
cli_hm_have_size(fp, CLI_HASH_MD5, ctx->fmap->len) ||
|
cli_hm_have_size(fp, CLI_HASH_MD5, ctx->fmap->len) ||
|
||||||
cli_hm_have_wild(hdb, CLI_HASH_MD5) ||
|
cli_hm_have_wild(fp, CLI_HASH_MD5);
|
||||||
cli_hm_have_wild(fp, CLI_HASH_MD5)) {
|
|
||||||
compute_hash[CLI_HASH_MD5] = true;
|
need_hash[CLI_HASH_SHA1] = cli_hm_have_size(hdb, CLI_HASH_SHA1, ctx->fmap->len) ||
|
||||||
} else {
|
cli_hm_have_wild(hdb, CLI_HASH_SHA1) ||
|
||||||
compute_hash[CLI_HASH_MD5] = false;
|
cli_hm_have_size(fp, CLI_HASH_SHA1, ctx->fmap->len) ||
|
||||||
|
cli_hm_have_wild(fp, CLI_HASH_SHA1);
|
||||||
|
|
||||||
|
need_hash[CLI_HASH_SHA2_256] = cli_hm_have_size(hdb, CLI_HASH_SHA2_256, ctx->fmap->len) ||
|
||||||
|
cli_hm_have_wild(hdb, CLI_HASH_SHA2_256) ||
|
||||||
|
cli_hm_have_size(fp, CLI_HASH_SHA2_256, ctx->fmap->len) ||
|
||||||
|
cli_hm_have_wild(fp, CLI_HASH_SHA2_256);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Initialize hash contexts for the hashes that we need to compute.
|
||||||
|
*/
|
||||||
|
for (hash_type = CLI_HASH_MD5; hash_type < CLI_HASH_AVAIL_TYPES; hash_type++) {
|
||||||
|
if (need_hash[hash_type] && !ctx->fmap->have_hash[hash_type]) {
|
||||||
|
const char *hash_name = cli_hash_name(hash_type);
|
||||||
|
|
||||||
|
hashctx[hash_type] = cl_hash_init(hash_name);
|
||||||
|
if (NULL == hashctx[hash_type]) {
|
||||||
|
cli_errmsg("cli_scan_fmap: Error initializing %s hash context\n", hash_name);
|
||||||
|
ret = CL_EARG;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
compute_hash[CLI_HASH_MD5] = 0;
|
|
||||||
memcpy(digest[CLI_HASH_MD5], refhash, 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cli_hm_have_size(hdb, CLI_HASH_SHA1, ctx->fmap->len) ||
|
|
||||||
cli_hm_have_wild(hdb, CLI_HASH_SHA1) ||
|
|
||||||
cli_hm_have_size(fp, CLI_HASH_SHA1, ctx->fmap->len) ||
|
|
||||||
cli_hm_have_wild(fp, CLI_HASH_SHA1)) {
|
|
||||||
compute_hash[CLI_HASH_SHA1] = true;
|
|
||||||
} else {
|
|
||||||
compute_hash[CLI_HASH_SHA1] = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cli_hm_have_size(hdb, CLI_HASH_SHA256, ctx->fmap->len) ||
|
|
||||||
cli_hm_have_wild(hdb, CLI_HASH_SHA256) ||
|
|
||||||
cli_hm_have_size(fp, CLI_HASH_SHA256, ctx->fmap->len) ||
|
|
||||||
cli_hm_have_wild(fp, CLI_HASH_SHA256)) {
|
|
||||||
compute_hash[CLI_HASH_SHA256] = true;
|
|
||||||
} else {
|
|
||||||
compute_hash[CLI_HASH_SHA256] = false;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1289,7 +1298,7 @@ cl_error_t cli_scan_fmap(cli_ctx *ctx, cli_file_t ftype, bool filetype_only, str
|
||||||
if (!(buff = fmap_need_off_once(ctx->fmap, offset, bytes)))
|
if (!(buff = fmap_need_off_once(ctx->fmap, offset, bytes)))
|
||||||
break;
|
break;
|
||||||
if (ctx->scanned)
|
if (ctx->scanned)
|
||||||
*ctx->scanned += bytes / CL_COUNT_PRECISION;
|
*ctx->scanned += bytes;
|
||||||
|
|
||||||
if (target_ac_root) {
|
if (target_ac_root) {
|
||||||
const char *virname = NULL;
|
const char *virname = NULL;
|
||||||
|
@ -1323,12 +1332,19 @@ cl_error_t cli_scan_fmap(cli_ctx *ctx, cli_file_t ftype, bool filetype_only, str
|
||||||
const void *data = buff + maxpatlen * (offset != 0);
|
const void *data = buff + maxpatlen * (offset != 0);
|
||||||
uint32_t data_len = bytes - maxpatlen * (offset != 0);
|
uint32_t data_len = bytes - maxpatlen * (offset != 0);
|
||||||
|
|
||||||
if (compute_hash[CLI_HASH_MD5])
|
for (hash_type = CLI_HASH_MD5; hash_type < CLI_HASH_AVAIL_TYPES; hash_type++) {
|
||||||
cl_update_hash(md5ctx, (void *)data, data_len);
|
/*
|
||||||
if (compute_hash[CLI_HASH_SHA1])
|
* Compute the hash for the current data chunk, if we need to.
|
||||||
cl_update_hash(sha1ctx, (void *)data, data_len);
|
*/
|
||||||
if (compute_hash[CLI_HASH_SHA256])
|
if (need_hash[hash_type] && !ctx->fmap->have_hash[hash_type]) {
|
||||||
cl_update_hash(sha256ctx, (void *)data, data_len);
|
if (cl_update_hash(hashctx[hash_type], data, data_len)) {
|
||||||
|
const char *hash_name = cli_hash_name(hash_type);
|
||||||
|
cli_errmsg("cli_scan_fmap: Error calculating %s hash!\n", hash_name);
|
||||||
|
ret = CL_EREAD;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1341,47 +1357,40 @@ cl_error_t cli_scan_fmap(cli_ctx *ctx, cli_file_t ftype, bool filetype_only, str
|
||||||
if (!filetype_only && hdb) {
|
if (!filetype_only && hdb) {
|
||||||
/* We're not just doing file typing, we're scanning for malware.
|
/* We're not just doing file typing, we're scanning for malware.
|
||||||
So we need to check the hash sigs, if there are any. */
|
So we need to check the hash sigs, if there are any. */
|
||||||
|
for (hash_type = CLI_HASH_MD5; hash_type < CLI_HASH_AVAIL_TYPES; hash_type++) {
|
||||||
|
/*
|
||||||
|
* Compute the hash for the current data chunk, if we need to.
|
||||||
|
*/
|
||||||
|
if (need_hash[hash_type] && !ctx->fmap->have_hash[hash_type]) {
|
||||||
|
cl_finish_hash(hashctx[hash_type], digest[hash_type]);
|
||||||
|
hashctx[hash_type] = NULL;
|
||||||
|
|
||||||
cli_hash_type_t hashtype;
|
fmap_set_hash(ctx->fmap, digest[hash_type], hash_type);
|
||||||
|
}
|
||||||
if (compute_hash[CLI_HASH_MD5]) {
|
|
||||||
cl_finish_hash(md5ctx, digest[CLI_HASH_MD5]);
|
|
||||||
md5ctx = NULL;
|
|
||||||
|
|
||||||
// Save the MD5 hash for later use (e.g. in FP checks).
|
|
||||||
fmap_set_hash(ctx->fmap, digest[CLI_HASH_MD5], CLI_HASH_MD5);
|
|
||||||
}
|
|
||||||
if (refhash) {
|
|
||||||
// Set "compute_hash" to 1 because we'll use this later to know if we have a hash to check.
|
|
||||||
compute_hash[CLI_HASH_MD5] = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (compute_hash[CLI_HASH_SHA1]) {
|
for (hash_type = CLI_HASH_MD5; hash_type < CLI_HASH_AVAIL_TYPES; hash_type++) {
|
||||||
cl_finish_hash(sha1ctx, digest[CLI_HASH_SHA1]);
|
|
||||||
sha1ctx = NULL;
|
|
||||||
|
|
||||||
// Save the SHA1 hash for later use (e.g. in FP checks).
|
|
||||||
fmap_set_hash(ctx->fmap, digest[CLI_HASH_SHA1], CLI_HASH_SHA1);
|
|
||||||
}
|
|
||||||
if (compute_hash[CLI_HASH_SHA256]) {
|
|
||||||
cl_finish_hash(sha256ctx, digest[CLI_HASH_SHA256]);
|
|
||||||
sha256ctx = NULL;
|
|
||||||
|
|
||||||
// Save the SHA256 hash for later use (e.g. in FP checks).
|
|
||||||
fmap_set_hash(ctx->fmap, digest[CLI_HASH_SHA256], CLI_HASH_SHA256);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (hashtype = CLI_HASH_MD5; hashtype < CLI_HASH_AVAIL_TYPES; hashtype++) {
|
|
||||||
const char *virname = NULL;
|
const char *virname = NULL;
|
||||||
const char *virname_w = NULL;
|
const char *virname_w = NULL;
|
||||||
|
uint8_t *hash = NULL;
|
||||||
|
|
||||||
/* If no hash, skip to next type */
|
/* If no hash, skip to next type */
|
||||||
if (!compute_hash[hashtype]) {
|
if (!need_hash[hash_type]) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Do hash scan checking hash sigs with specific size */
|
/* Get the hash for the current type.
|
||||||
ret = cli_hm_scan(digest[hashtype], ctx->fmap->len, &virname, hdb, hashtype);
|
* We already calculated all the needed ones, so this is a simple lookup.
|
||||||
|
* Yes, I know there is the digest[] array, but that one may be hashes calculated before this function. */
|
||||||
|
ret = fmap_get_hash(ctx->fmap, &hash, hash_type);
|
||||||
|
if (CL_SUCCESS != ret) {
|
||||||
|
cli_dbgmsg("cli_scan_fmap: Error getting hash for type %d\n", hash_type);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Do hash scan checking hash sigs with specific size.
|
||||||
|
* This part is fast, so we aren't checking if there are any of hash sigs for this type of hash at this file size */
|
||||||
|
ret = cli_hm_scan(hash, ctx->fmap->len, &virname, hdb, hash_type);
|
||||||
if (ret == CL_VIRUS) {
|
if (ret == CL_VIRUS) {
|
||||||
/* Matched with size-based hash ... */
|
/* Matched with size-based hash ... */
|
||||||
ret = cli_append_virus(ctx, virname);
|
ret = cli_append_virus(ctx, virname);
|
||||||
|
@ -1390,8 +1399,9 @@ cl_error_t cli_scan_fmap(cli_ctx *ctx, cli_file_t ftype, bool filetype_only, str
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Do hash scan checking hash sigs with wildcard size */
|
/* Do hash scan checking hash sigs with wildcard size.
|
||||||
ret = cli_hm_scan_wild(digest[hashtype], &virname_w, hdb, hashtype);
|
* This part is fast, so we aren't checking if there are any hash sigs for this type of hash with wildcard size */
|
||||||
|
ret = cli_hm_scan_wild(hash, &virname_w, hdb, hash_type);
|
||||||
if (ret == CL_VIRUS) {
|
if (ret == CL_VIRUS) {
|
||||||
/* Matched with size-agnostic hash ... */
|
/* Matched with size-agnostic hash ... */
|
||||||
ret = cli_append_virus(ctx, virname_w);
|
ret = cli_append_virus(ctx, virname_w);
|
||||||
|
@ -1408,26 +1418,22 @@ cl_error_t cli_scan_fmap(cli_ctx *ctx, cli_file_t ftype, bool filetype_only, str
|
||||||
// Evaluate for the target-specific signature AC matches.
|
// Evaluate for the target-specific signature AC matches.
|
||||||
if (NULL != target_ac_root) {
|
if (NULL != target_ac_root) {
|
||||||
if (ret != CL_VIRUS) {
|
if (ret != CL_VIRUS) {
|
||||||
ret = cli_exp_eval(ctx, target_ac_root, &target_ac_data, &info, (const char *)refhash);
|
ret = cli_exp_eval(ctx, target_ac_root, &target_ac_data, &info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Evaluate for the generic signature AC matches.
|
// Evaluate for the generic signature AC matches.
|
||||||
if (NULL != generic_ac_root) {
|
if (NULL != generic_ac_root) {
|
||||||
if (ret != CL_VIRUS) {
|
if (ret != CL_VIRUS) {
|
||||||
ret = cli_exp_eval(ctx, generic_ac_root, &generic_ac_data, &info, (const char *)refhash);
|
ret = cli_exp_eval(ctx, generic_ac_root, &generic_ac_data, &info);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
if (NULL != md5ctx) {
|
for (hash_type = CLI_HASH_MD5; hash_type < CLI_HASH_AVAIL_TYPES; hash_type++) {
|
||||||
cl_hash_destroy(md5ctx);
|
if (NULL != hashctx[hash_type]) {
|
||||||
}
|
cl_hash_destroy(hashctx[hash_type]);
|
||||||
if (NULL != sha1ctx) {
|
}
|
||||||
cl_hash_destroy(sha1ctx);
|
|
||||||
}
|
|
||||||
if (NULL != sha256ctx) {
|
|
||||||
cl_hash_destroy(sha256ctx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (gdata_initialized) {
|
if (gdata_initialized) {
|
||||||
|
|
|
@ -322,7 +322,7 @@ cl_error_t cli_scan_buff(const unsigned char *buffer, uint32_t length, uint32_t
|
||||||
* @param attributes Layer attributes for the thing to be scanned.
|
* @param attributes Layer attributes for the thing to be scanned.
|
||||||
* @return cl_error_t
|
* @return cl_error_t
|
||||||
*/
|
*/
|
||||||
cl_error_t cli_scan_desc(int desc, cli_ctx *ctx, cli_file_t ftype, bool filetype_only, struct cli_matched_type **ftoffset, unsigned int acmode, struct cli_ac_result **acres, const char *name, uint32_t attributes);
|
cl_error_t cli_scan_desc(int desc, cli_ctx *ctx, cli_file_t ftype, bool filetype_only, struct cli_matched_type **ftoffset, unsigned int acmode, struct cli_ac_result **acres, const char *name, const char *path, uint32_t attributes);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Non-magic scan matching of the current fmap in the scan context. Newer API.
|
* @brief Non-magic scan matching of the current fmap in the scan context. Newer API.
|
||||||
|
@ -343,10 +343,9 @@ cl_error_t cli_scan_desc(int desc, cli_ctx *ctx, cli_file_t ftype, bool filetype
|
||||||
* @param[out] ftoffset (optional) A list of file type signature matches with their corresponding offsets. If provided, will output the file type signature matches.
|
* @param[out] ftoffset (optional) A list of file type signature matches with their corresponding offsets. If provided, will output the file type signature matches.
|
||||||
* @param acmode Use AC_SCAN_VIR and AC_SCAN_FT to set scanning modes.
|
* @param acmode Use AC_SCAN_VIR and AC_SCAN_FT to set scanning modes.
|
||||||
* @param[out] acres A list of cli_ac_result AC pattern matching results.
|
* @param[out] acres A list of cli_ac_result AC pattern matching results.
|
||||||
* @param refhash MD5 hash of the current file, used to save time creating hashes and to limit scan recursion for the HandlerType logical signature FTM feature.
|
|
||||||
* @return cl_error_t
|
* @return cl_error_t
|
||||||
*/
|
*/
|
||||||
cl_error_t cli_scan_fmap(cli_ctx *ctx, cli_file_t ftype, bool filetype_only, struct cli_matched_type **ftoffset, unsigned int acmode, struct cli_ac_result **acres, unsigned char *refhash);
|
cl_error_t cli_scan_fmap(cli_ctx *ctx, cli_file_t ftype, bool filetype_only, struct cli_matched_type **ftoffset, unsigned int acmode, struct cli_ac_result **acres);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Evaluate logical signatures and yara rules given the AC matching results
|
* @brief Evaluate logical signatures and yara rules given the AC matching results
|
||||||
|
@ -359,12 +358,12 @@ cl_error_t cli_scan_fmap(cli_ctx *ctx, cli_file_t ftype, bool filetype_only, str
|
||||||
* @param hash Reference hash of the current file, used to limit recursion for the HandlerType logical signature FTM feature.
|
* @param hash Reference hash of the current file, used to limit recursion for the HandlerType logical signature FTM feature.
|
||||||
* @return cl_error_t
|
* @return cl_error_t
|
||||||
*/
|
*/
|
||||||
cl_error_t cli_exp_eval(cli_ctx *ctx, struct cli_matcher *root, struct cli_ac_data *acdata, struct cli_target_info *target_info, const char *hash);
|
cl_error_t cli_exp_eval(cli_ctx *ctx, struct cli_matcher *root, struct cli_ac_data *acdata, struct cli_target_info *target_info);
|
||||||
|
|
||||||
cl_error_t cli_caloff(const char *offstr, const struct cli_target_info *info, unsigned int target, uint32_t *offdata, uint32_t *offset_min, uint32_t *offset_max);
|
cl_error_t cli_caloff(const char *offstr, const struct cli_target_info *info, cli_target_t target, uint32_t *offdata, uint32_t *offset_min, uint32_t *offset_max);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Determine if an alert is a known false positive, using each fmap in the ctx->container stack to check MD5, SHA1, and SHA256 hashes.
|
* @brief Determine if an alert is a known false positive, using each fmap in the ctx->container stack to check MD5, SHA1, and SHA2-256 hashes.
|
||||||
*
|
*
|
||||||
* @param ctx The scanning context.
|
* @param ctx The scanning context.
|
||||||
* @param vname (Optional) The name of the signature alert.
|
* @param vname (Optional) The name of the signature alert.
|
||||||
|
|
|
@ -381,7 +381,7 @@ cli_parse_mbox(const char *dir, cli_ctx *ctx)
|
||||||
mctx.subtypeTable = subtype;
|
mctx.subtypeTable = subtype;
|
||||||
mctx.ctx = ctx;
|
mctx.ctx = ctx;
|
||||||
mctx.files = 0;
|
mctx.files = 0;
|
||||||
mctx.wrkobj = ctx->wrkproperty;
|
mctx.wrkobj = ctx->this_layer_metadata_json;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Is it a UNIX style mbox with more than one
|
* Is it a UNIX style mbox with more than one
|
||||||
|
@ -1457,8 +1457,8 @@ static cl_error_t parseMHTMLComment(const char *comment, cli_ctx *ctx, void *wrk
|
||||||
if (!reader) {
|
if (!reader) {
|
||||||
cli_dbgmsg("parseMHTMLComment: cannot initialize xmlReader\n");
|
cli_dbgmsg("parseMHTMLComment: cannot initialize xmlReader\n");
|
||||||
|
|
||||||
if (ctx->wrkproperty != NULL)
|
if (ctx->this_layer_metadata_json != NULL)
|
||||||
ret = cli_json_parse_error(ctx->wrkproperty, "MHTML_ERROR_XML_READER_MEM");
|
ret = cli_json_parse_error(ctx->this_layer_metadata_json, "MHTML_ERROR_XML_READER_MEM");
|
||||||
|
|
||||||
return ret; // libxml2 failed!
|
return ret; // libxml2 failed!
|
||||||
}
|
}
|
||||||
|
@ -1515,8 +1515,8 @@ parseRootMHTML(mbox_ctx *mctx, message *m, text *t)
|
||||||
if (htmlDoc == NULL) {
|
if (htmlDoc == NULL) {
|
||||||
cli_dbgmsg("parseRootMHTML: cannot initialize read html document\n");
|
cli_dbgmsg("parseRootMHTML: cannot initialize read html document\n");
|
||||||
|
|
||||||
if (ctx->wrkproperty != NULL)
|
if (ctx->this_layer_metadata_json != NULL)
|
||||||
ret = cli_json_parse_error(ctx->wrkproperty, "MHTML_ERROR_HTML_READ");
|
ret = cli_json_parse_error(ctx->this_layer_metadata_json, "MHTML_ERROR_HTML_READ");
|
||||||
if (ret != CL_SUCCESS)
|
if (ret != CL_SUCCESS)
|
||||||
rc = FAIL;
|
rc = FAIL;
|
||||||
|
|
||||||
|
@ -1537,8 +1537,8 @@ parseRootMHTML(mbox_ctx *mctx, message *m, text *t)
|
||||||
if (reader == NULL) {
|
if (reader == NULL) {
|
||||||
cli_dbgmsg("parseRootMHTML: cannot initialize xmlTextReader\n");
|
cli_dbgmsg("parseRootMHTML: cannot initialize xmlTextReader\n");
|
||||||
|
|
||||||
if (ctx->wrkproperty != NULL)
|
if (ctx->this_layer_metadata_json != NULL)
|
||||||
ret = cli_json_parse_error(ctx->wrkproperty, "MHTML_ERROR_XML_READER_IO");
|
ret = cli_json_parse_error(ctx->this_layer_metadata_json, "MHTML_ERROR_XML_READER_IO");
|
||||||
if (ret != CL_SUCCESS)
|
if (ret != CL_SUCCESS)
|
||||||
rc = FAIL;
|
rc = FAIL;
|
||||||
|
|
||||||
|
@ -2262,7 +2262,7 @@ parseEmailBody(message *messageIn, text *textIn, mbox_ctx *mctx, unsigned int re
|
||||||
cli_dbgmsg("No HTML code found to be scanned\n");
|
cli_dbgmsg("No HTML code found to be scanned\n");
|
||||||
} else {
|
} else {
|
||||||
/* Send root HTML file for preclassification */
|
/* Send root HTML file for preclassification */
|
||||||
if (mctx->ctx->wrkproperty)
|
if (mctx->ctx->this_layer_metadata_json)
|
||||||
(void)parseRootMHTML(mctx, messages[htmltextPart], aText);
|
(void)parseRootMHTML(mctx, messages[htmltextPart], aText);
|
||||||
|
|
||||||
rc = parseEmailBody(messages[htmltextPart], aText, mctx, recursion_level + 1);
|
rc = parseEmailBody(messages[htmltextPart], aText, mctx, recursion_level + 1);
|
||||||
|
@ -3831,7 +3831,7 @@ getHrefs(cli_ctx *ctx, message *m, tag_arguments_t *hrefs)
|
||||||
|
|
||||||
/* TODO: make this size customisable */
|
/* TODO: make this size customisable */
|
||||||
if (len > 100 * 1024) {
|
if (len > 100 * 1024) {
|
||||||
cli_dbgmsg("Viruses pointed to by URLs not scanned in large message\n");
|
cli_dbgmsg("HTML pointed to by URLs not scanned in large message\n");
|
||||||
blobDestroy(b);
|
blobDestroy(b);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -4448,7 +4448,7 @@ do_multipart(message *mainMessage, message **messages, int i, mbox_status *rc, m
|
||||||
|
|
||||||
if (thisobj != NULL) {
|
if (thisobj != NULL) {
|
||||||
/* attempt to determine container size - prevents incorrect type reporting */
|
/* attempt to determine container size - prevents incorrect type reporting */
|
||||||
if (json_object_object_get_ex(mctx->ctx->wrkproperty, "ContainedObjects", &arrobj)) {
|
if (json_object_object_get_ex(mctx->ctx->this_layer_metadata_json, "ContainedObjects", &arrobj)) {
|
||||||
arrlen = json_object_array_length(arrobj);
|
arrlen = json_object_array_length(arrobj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4469,7 +4469,7 @@ do_multipart(message *mainMessage, message **messages, int i, mbox_status *rc, m
|
||||||
const char *dtype = NULL;
|
const char *dtype = NULL;
|
||||||
|
|
||||||
/* attempt to acquire container type */
|
/* attempt to acquire container type */
|
||||||
if (json_object_object_get_ex(mctx->ctx->wrkproperty, "ContainedObjects", &arrobj)) {
|
if (json_object_object_get_ex(mctx->ctx->this_layer_metadata_json, "ContainedObjects", &arrobj)) {
|
||||||
if (json_object_array_length(arrobj) > arrlen) {
|
if (json_object_array_length(arrobj) > arrlen) {
|
||||||
entry = json_object_array_get_idx(arrobj, arrlen);
|
entry = json_object_array_get_idx(arrobj, arrlen);
|
||||||
}
|
}
|
||||||
|
|
|
@ -279,7 +279,6 @@ static cl_error_t mbr_scanextprtn(cli_ctx *ctx, unsigned *prtncount, size_t extl
|
||||||
/* EBR checks */
|
/* EBR checks */
|
||||||
status = mbr_check_ebr(&ebr);
|
status = mbr_check_ebr(&ebr);
|
||||||
if (status != CL_SUCCESS) {
|
if (status != CL_SUCCESS) {
|
||||||
status = status;
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -379,7 +378,6 @@ static cl_error_t mbr_scanextprtn(cli_ctx *ctx, unsigned *prtncount, size_t extl
|
||||||
|
|
||||||
status = cli_magic_scan_nested_fmap_type(ctx->fmap, partoff, partsize, ctx, CL_TYPE_PART_ANY, NULL, LAYER_ATTRIBUTES_NONE);
|
status = cli_magic_scan_nested_fmap_type(ctx->fmap, partoff, partsize, ctx, CL_TYPE_PART_ANY, NULL, LAYER_ATTRIBUTES_NONE);
|
||||||
if (status != CL_SUCCESS) {
|
if (status != CL_SUCCESS) {
|
||||||
status = status;
|
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -813,7 +813,7 @@ static int cli_ole2_summary_json_cleanup(summary_ctx_t *sctx, int retcode)
|
||||||
cli_dbgmsg("in cli_ole2_summary_json_cleanup: %d[%x]\n", retcode, sctx->flags);
|
cli_dbgmsg("in cli_ole2_summary_json_cleanup: %d[%x]\n", retcode, sctx->flags);
|
||||||
|
|
||||||
if (sctx->sfmap) {
|
if (sctx->sfmap) {
|
||||||
funmap(sctx->sfmap);
|
fmap_free(sctx->sfmap);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sctx->flags) {
|
if (sctx->flags) {
|
||||||
|
@ -872,7 +872,7 @@ static int cli_ole2_summary_json_cleanup(summary_ctx_t *sctx, int retcode)
|
||||||
return retcode;
|
return retcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
int cli_ole2_summary_json(cli_ctx *ctx, int fd, int mode)
|
int cli_ole2_summary_json(cli_ctx *ctx, int fd, int mode, const char *filepath)
|
||||||
{
|
{
|
||||||
summary_ctx_t sctx;
|
summary_ctx_t sctx;
|
||||||
STATBUF statbuf;
|
STATBUF statbuf;
|
||||||
|
@ -909,7 +909,7 @@ int cli_ole2_summary_json(cli_ctx *ctx, int fd, int mode)
|
||||||
return CL_ESTAT;
|
return CL_ESTAT;
|
||||||
}
|
}
|
||||||
|
|
||||||
sctx.sfmap = fmap(fd, 0, statbuf.st_size, NULL);
|
sctx.sfmap = fmap_new(fd, 0, statbuf.st_size, NULL, filepath);
|
||||||
if (!sctx.sfmap) {
|
if (!sctx.sfmap) {
|
||||||
cli_dbgmsg("ole2_summary_json: failed to get fmap\n");
|
cli_dbgmsg("ole2_summary_json: failed to get fmap\n");
|
||||||
return CL_EMAP;
|
return CL_EMAP;
|
||||||
|
@ -919,14 +919,14 @@ int cli_ole2_summary_json(cli_ctx *ctx, int fd, int mode)
|
||||||
|
|
||||||
switch (mode) {
|
switch (mode) {
|
||||||
case 1:
|
case 1:
|
||||||
sctx.summary = cli_jsonobj(ctx->wrkproperty, "DocSummaryInfo");
|
sctx.summary = cli_jsonobj(ctx->this_layer_metadata_json, "DocSummaryInfo");
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
sctx.summary = cli_jsonobj(ctx->wrkproperty, "Hwp5SummaryInfo");
|
sctx.summary = cli_jsonobj(ctx->this_layer_metadata_json, "Hwp5SummaryInfo");
|
||||||
break;
|
break;
|
||||||
case 0:
|
case 0:
|
||||||
default:
|
default:
|
||||||
sctx.summary = cli_jsonobj(ctx->wrkproperty, "SummaryInfo");
|
sctx.summary = cli_jsonobj(ctx->this_layer_metadata_json, "SummaryInfo");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -991,7 +991,7 @@ int cli_ole2_summary_json(cli_ctx *ctx, int fd, int mode)
|
||||||
|
|
||||||
/* second property set (index=1) is always a custom property set (if present) */
|
/* second property set (index=1) is always a custom property set (if present) */
|
||||||
if (sumstub.num_propsets == 2) {
|
if (sumstub.num_propsets == 2) {
|
||||||
cli_jsonbool(ctx->wrkproperty, "HasUserDefinedProperties", 1);
|
cli_jsonbool(ctx->this_layer_metadata_json, "HasUserDefinedProperties", 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
return cli_ole2_summary_json_cleanup(&sctx, CL_SUCCESS);
|
return cli_ole2_summary_json_cleanup(&sctx, CL_SUCCESS);
|
||||||
|
|
|
@ -166,6 +166,6 @@ typedef struct summary_ctx {
|
||||||
} summary_ctx_t;
|
} summary_ctx_t;
|
||||||
|
|
||||||
/* Summary and Document Information Parsing to JSON */
|
/* Summary and Document Information Parsing to JSON */
|
||||||
int cli_ole2_summary_json(cli_ctx *ctx, int fd, int mode);
|
int cli_ole2_summary_json(cli_ctx *ctx, int fd, int mode, const char *filepath);
|
||||||
|
|
||||||
#endif /* __MSDOC_H_ */
|
#endif /* __MSDOC_H_ */
|
||||||
|
|
|
@ -241,7 +241,7 @@ cl_error_t cli_scanmsxml(cli_ctx *ctx)
|
||||||
if (!reader) {
|
if (!reader) {
|
||||||
cli_dbgmsg("cli_scanmsxml: cannot initialize xmlReader\n");
|
cli_dbgmsg("cli_scanmsxml: cannot initialize xmlReader\n");
|
||||||
|
|
||||||
ret = cli_json_parse_error(ctx->wrkproperty, "OOXML_ERROR_XML_READER_IO");
|
ret = cli_json_parse_error(ctx->this_layer_metadata_json, "OOXML_ERROR_XML_READER_IO");
|
||||||
|
|
||||||
return ret; // libxml2 failed!
|
return ret; // libxml2 failed!
|
||||||
}
|
}
|
||||||
|
|
|
@ -383,7 +383,7 @@ static cl_error_t msxml_parse_element(struct msxml_ctx *mxctx, xmlTextReaderPtr
|
||||||
|
|
||||||
cli_msxmlmsg("BINARY CALLBACK DATA!\n");
|
cli_msxmlmsg("BINARY CALLBACK DATA!\n");
|
||||||
|
|
||||||
if ((ret = cli_gentempfd(ctx->sub_tmpdir, &tempfile, &of)) != CL_SUCCESS) {
|
if ((ret = cli_gentempfd(ctx->this_layer_tmpdir, &tempfile, &of)) != CL_SUCCESS) {
|
||||||
cli_warnmsg("msxml_parse_element: failed to create temporary file %s\n", tempfile);
|
cli_warnmsg("msxml_parse_element: failed to create temporary file %s\n", tempfile);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -426,7 +426,7 @@ static cl_error_t msxml_parse_element(struct msxml_ctx *mxctx, xmlTextReaderPtr
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((ret = cli_gentempfd(ctx->sub_tmpdir, &tempfile, &of)) != CL_SUCCESS) {
|
if ((ret = cli_gentempfd(ctx->this_layer_tmpdir, &tempfile, &of)) != CL_SUCCESS) {
|
||||||
cli_warnmsg("msxml_parse_element: failed to create temporary file %s\n", tempfile);
|
cli_warnmsg("msxml_parse_element: failed to create temporary file %s\n", tempfile);
|
||||||
free(decoded);
|
free(decoded);
|
||||||
return ret;
|
return ret;
|
||||||
|
@ -554,7 +554,7 @@ cl_error_t cli_msxml_parse_document(cli_ctx *ctx, xmlTextReaderPtr reader, const
|
||||||
ictx.num_keys = num_keys;
|
ictx.num_keys = num_keys;
|
||||||
|
|
||||||
if (flags & MSXML_FLAG_JSON) {
|
if (flags & MSXML_FLAG_JSON) {
|
||||||
ictx.root = ctx->wrkproperty;
|
ictx.root = ctx->this_layer_metadata_json;
|
||||||
/* JSON Sanity Check */
|
/* JSON Sanity Check */
|
||||||
if (!ictx.root)
|
if (!ictx.root)
|
||||||
ictx.flags &= ~MSXML_FLAG_JSON;
|
ictx.flags &= ~MSXML_FLAG_JSON;
|
||||||
|
|
|
@ -521,7 +521,7 @@ int cli_scannulsft(cli_ctx *ctx, off_t offset)
|
||||||
memset(&nsist, 0, sizeof(struct nsis_st));
|
memset(&nsist, 0, sizeof(struct nsis_st));
|
||||||
|
|
||||||
nsist.off = offset;
|
nsist.off = offset;
|
||||||
if (!(nsist.dir = cli_gentemp_with_prefix(ctx->sub_tmpdir, "nulsft-tmp")))
|
if (!(nsist.dir = cli_gentemp_with_prefix(ctx->this_layer_tmpdir, "nulsft-tmp")))
|
||||||
return CL_ETMPDIR;
|
return CL_ETMPDIR;
|
||||||
if (mkdir(nsist.dir, 0700)) {
|
if (mkdir(nsist.dir, 0700)) {
|
||||||
cli_dbgmsg("NSIS: Can't create temporary directory %s\n", nsist.dir);
|
cli_dbgmsg("NSIS: Can't create temporary directory %s\n", nsist.dir);
|
||||||
|
@ -539,18 +539,31 @@ int cli_scannulsft(cli_ctx *ctx, off_t offset)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (ret == CL_SUCCESS) {
|
if (ret == CL_SUCCESS) {
|
||||||
|
char *name = NULL;
|
||||||
cli_dbgmsg("NSIS: Successfully extracted file #%u\n", nsist.fno);
|
cli_dbgmsg("NSIS: Successfully extracted file #%u\n", nsist.fno);
|
||||||
if (lseek(nsist.ofd, 0, SEEK_SET) == -1) {
|
if (lseek(nsist.ofd, 0, SEEK_SET) == -1) {
|
||||||
cli_dbgmsg("NSIS: call to lseek() failed\n");
|
cli_dbgmsg("NSIS: call to lseek() failed\n");
|
||||||
free(nsist.dir);
|
free(nsist.dir);
|
||||||
return CL_ESEEK;
|
return CL_ESEEK;
|
||||||
}
|
}
|
||||||
if (nsist.fno == 1) {
|
|
||||||
ret = cli_scan_desc(nsist.ofd, ctx, CL_TYPE_ANY, false, NULL, AC_SCAN_VIR, NULL, NULL, LAYER_ATTRIBUTES_NONE); /// TODO: Extract file names
|
// Get basename of the file from nsist.ofn
|
||||||
} else {
|
ret = cli_basename(nsist.ofn, strlen(nsist.ofn), &name, true /* posix_support_backslash_pathsep */);
|
||||||
ret = cli_magic_scan_desc(nsist.ofd, nsist.ofn, ctx, NULL, LAYER_ATTRIBUTES_NONE); /// TODO: Extract file names
|
if (CL_SUCCESS != ret || NULL == name) {
|
||||||
|
cli_dbgmsg("NSIS: Failed to get basename of the file\n");
|
||||||
|
// If it fails, the name will just be NULL. That's okay.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (nsist.fno == 1) {
|
||||||
|
ret = cli_scan_desc(nsist.ofd, ctx, CL_TYPE_ANY, false, NULL, AC_SCAN_VIR, NULL, name, nsist.ofn, LAYER_ATTRIBUTES_NONE); /// TODO: Extract file names
|
||||||
|
} else {
|
||||||
|
ret = cli_magic_scan_desc(nsist.ofd, nsist.ofn, ctx, name, LAYER_ATTRIBUTES_NONE); /// TODO: Extract file names
|
||||||
|
}
|
||||||
|
|
||||||
|
CLI_FREE_AND_SET_NULL(name);
|
||||||
|
|
||||||
close(nsist.ofd);
|
close(nsist.ofd);
|
||||||
|
|
||||||
if (!ctx->engine->keeptmp) {
|
if (!ctx->engine->keeptmp) {
|
||||||
if (cli_unlink(nsist.ofn)) {
|
if (cli_unlink(nsist.ofn)) {
|
||||||
ret = CL_EUNLINK;
|
ret = CL_EUNLINK;
|
||||||
|
|
|
@ -1065,12 +1065,12 @@ static int ole2_walk_property_tree(ole2_header_t *hdr, const char *dir, int32_t
|
||||||
case 1: /* Directory */
|
case 1: /* Directory */
|
||||||
ole2_listmsg("directory node\n");
|
ole2_listmsg("directory node\n");
|
||||||
if (dir) {
|
if (dir) {
|
||||||
if (SCAN_COLLECT_METADATA && (ctx->wrkproperty != NULL)) {
|
if (SCAN_COLLECT_METADATA && (ctx->this_layer_metadata_json != NULL)) {
|
||||||
if (!json_object_object_get_ex(ctx->wrkproperty, "DigitalSignatures", NULL)) {
|
if (!json_object_object_get_ex(ctx->this_layer_metadata_json, "DigitalSignatures", NULL)) {
|
||||||
name = cli_ole2_get_property_name2(prop_block[idx].name, prop_block[idx].name_size);
|
name = cli_ole2_get_property_name2(prop_block[idx].name, prop_block[idx].name_size);
|
||||||
if (name) {
|
if (name) {
|
||||||
if (!strcmp(name, "_xmlsignatures") || !strcmp(name, "_signatures")) {
|
if (!strcmp(name, "_xmlsignatures") || !strcmp(name, "_signatures")) {
|
||||||
cli_jsonbool(ctx->wrkproperty, "HasDigitalSignatures", 1);
|
cli_jsonbool(ctx->this_layer_metadata_json, "HasDigitalSignatures", 1);
|
||||||
}
|
}
|
||||||
free(name);
|
free(name);
|
||||||
}
|
}
|
||||||
|
@ -1352,8 +1352,8 @@ static cl_error_t scan_biff_for_xlm_macros_and_images(
|
||||||
state->tmp = buff[i] & 0x20;
|
state->tmp = buff[i] & 0x20;
|
||||||
} else if ((state->data_offset == 14 || state->data_offset == 15) && state->tmp) {
|
} else if ((state->data_offset == 14 || state->data_offset == 15) && state->tmp) {
|
||||||
if (buff[i] == 1 || buff[i] == 2) {
|
if (buff[i] == 1 || buff[i] == 2) {
|
||||||
if (SCAN_COLLECT_METADATA && (ctx->wrkproperty != NULL)) {
|
if (SCAN_COLLECT_METADATA && (ctx->this_layer_metadata_json != NULL)) {
|
||||||
json_object *indicators = cli_jsonarray(ctx->wrkproperty, "MacroIndicators");
|
json_object *indicators = cli_jsonarray(ctx->this_layer_metadata_json, "MacroIndicators");
|
||||||
if (indicators) {
|
if (indicators) {
|
||||||
cli_jsonstr(indicators, NULL, "autorun");
|
cli_jsonstr(indicators, NULL, "autorun");
|
||||||
} else {
|
} else {
|
||||||
|
@ -1373,16 +1373,16 @@ static cl_error_t scan_biff_for_xlm_macros_and_images(
|
||||||
} else if (state->data_offset == 5 && buff[i] == 1) { // Excel 4.0 macro sheet
|
} else if (state->data_offset == 5 && buff[i] == 1) { // Excel 4.0 macro sheet
|
||||||
cli_dbgmsg("[scan_biff_for_xlm_macros_and_images] Found XLM macro sheet\n");
|
cli_dbgmsg("[scan_biff_for_xlm_macros_and_images] Found XLM macro sheet\n");
|
||||||
|
|
||||||
if (SCAN_COLLECT_METADATA && (ctx->wrkproperty != NULL)) {
|
if (SCAN_COLLECT_METADATA && (ctx->this_layer_metadata_json != NULL)) {
|
||||||
cli_jsonbool(ctx->wrkproperty, "HasMacros", 1);
|
cli_jsonbool(ctx->this_layer_metadata_json, "HasMacros", 1);
|
||||||
json_object *macro_languages = cli_jsonarray(ctx->wrkproperty, "MacroLanguages");
|
json_object *macro_languages = cli_jsonarray(ctx->this_layer_metadata_json, "MacroLanguages");
|
||||||
if (macro_languages) {
|
if (macro_languages) {
|
||||||
cli_jsonstr(macro_languages, NULL, "XLM");
|
cli_jsonstr(macro_languages, NULL, "XLM");
|
||||||
} else {
|
} else {
|
||||||
cli_dbgmsg("[scan_biff_for_xlm_macros_and_images] Failed to add \"XLM\" entry to MacroLanguages JSON array\n");
|
cli_dbgmsg("[scan_biff_for_xlm_macros_and_images] Failed to add \"XLM\" entry to MacroLanguages JSON array\n");
|
||||||
}
|
}
|
||||||
if (state->tmp == 1 || state->tmp == 2) {
|
if (state->tmp == 1 || state->tmp == 2) {
|
||||||
json_object *indicators = cli_jsonarray(ctx->wrkproperty, "MacroIndicators");
|
json_object *indicators = cli_jsonarray(ctx->this_layer_metadata_json, "MacroIndicators");
|
||||||
if (indicators) {
|
if (indicators) {
|
||||||
cli_jsonstr(indicators, NULL, "hidden");
|
cli_jsonstr(indicators, NULL, "hidden");
|
||||||
} else {
|
} else {
|
||||||
|
@ -1537,8 +1537,8 @@ static cl_error_t handler_enum(ole2_header_t *hdr, property_t *prop, const char
|
||||||
|
|
||||||
name = cli_ole2_get_property_name2(prop->name, prop->name_size);
|
name = cli_ole2_get_property_name2(prop->name, prop->name_size);
|
||||||
if (name) {
|
if (name) {
|
||||||
if (SCAN_COLLECT_METADATA && ctx->wrkproperty != NULL) {
|
if (SCAN_COLLECT_METADATA && ctx->this_layer_metadata_json != NULL) {
|
||||||
arrobj = cli_jsonarray(ctx->wrkproperty, "Streams");
|
arrobj = cli_jsonarray(ctx->this_layer_metadata_json, "Streams");
|
||||||
if (NULL == arrobj) {
|
if (NULL == arrobj) {
|
||||||
cli_warnmsg("ole2: no memory for streams list or streams is not an array\n");
|
cli_warnmsg("ole2: no memory for streams list or streams is not an array\n");
|
||||||
} else {
|
} else {
|
||||||
|
@ -1547,13 +1547,13 @@ static cl_error_t handler_enum(ole2_header_t *hdr, property_t *prop, const char
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!strcmp(name, "powerpoint document")) {
|
if (!strcmp(name, "powerpoint document")) {
|
||||||
cli_jsonstr(ctx->wrkproperty, "FileType", "CL_TYPE_MSPPT");
|
cli_jsonstr(ctx->this_layer_metadata_json, "FileType", "CL_TYPE_MSPPT");
|
||||||
}
|
}
|
||||||
if (!strcmp(name, "worddocument")) {
|
if (!strcmp(name, "worddocument")) {
|
||||||
cli_jsonstr(ctx->wrkproperty, "FileType", "CL_TYPE_MSWORD");
|
cli_jsonstr(ctx->this_layer_metadata_json, "FileType", "CL_TYPE_MSWORD");
|
||||||
}
|
}
|
||||||
if (!strcmp(name, "workbook")) {
|
if (!strcmp(name, "workbook")) {
|
||||||
cli_jsonstr(ctx->wrkproperty, "FileType", "CL_TYPE_MSXL");
|
cli_jsonstr(ctx->this_layer_metadata_json, "FileType", "CL_TYPE_MSXL");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1609,7 +1609,7 @@ static cl_error_t handler_enum(ole2_header_t *hdr, property_t *prop, const char
|
||||||
if (!memcmp(hwp_check + offset, "HWP Document File", 17)) {
|
if (!memcmp(hwp_check + offset, "HWP Document File", 17)) {
|
||||||
hwp5_header_t *hwp_new;
|
hwp5_header_t *hwp_new;
|
||||||
|
|
||||||
cli_jsonstr(ctx->wrkproperty, "FileType", "CL_TYPE_HWP5");
|
cli_jsonstr(ctx->this_layer_metadata_json, "FileType", "CL_TYPE_HWP5");
|
||||||
|
|
||||||
CLI_CALLOC_OR_GOTO_DONE(hwp_new, 1, sizeof(hwp5_header_t), status = CL_EMEM);
|
CLI_CALLOC_OR_GOTO_DONE(hwp_new, 1, sizeof(hwp5_header_t), status = CL_EMEM);
|
||||||
|
|
||||||
|
@ -1680,7 +1680,7 @@ likely_mso_stream(int fd)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static cl_error_t scan_mso_stream(int fd, cli_ctx *ctx)
|
static cl_error_t scan_mso_stream(int fd, const char *filepath, cli_ctx *ctx)
|
||||||
{
|
{
|
||||||
int zret, ofd;
|
int zret, ofd;
|
||||||
cl_error_t ret = CL_SUCCESS;
|
cl_error_t ret = CL_SUCCESS;
|
||||||
|
@ -1704,7 +1704,7 @@ static cl_error_t scan_mso_stream(int fd, cli_ctx *ctx)
|
||||||
return CL_ESTAT;
|
return CL_ESTAT;
|
||||||
}
|
}
|
||||||
|
|
||||||
input = fmap(fd, 0, statbuf.st_size, NULL);
|
input = fmap_new(fd, 0, statbuf.st_size, NULL, filepath);
|
||||||
if (!input) {
|
if (!input) {
|
||||||
cli_dbgmsg("scan_mso_stream: Failed to get fmap for input stream\n");
|
cli_dbgmsg("scan_mso_stream: Failed to get fmap for input stream\n");
|
||||||
return CL_EMAP;
|
return CL_EMAP;
|
||||||
|
@ -1712,9 +1712,9 @@ static cl_error_t scan_mso_stream(int fd, cli_ctx *ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* reserve tempfile for output and scanning */
|
/* reserve tempfile for output and scanning */
|
||||||
if ((ret = cli_gentempfd(ctx->sub_tmpdir, &tmpname, &ofd)) != CL_SUCCESS) {
|
if ((ret = cli_gentempfd(ctx->this_layer_tmpdir, &tmpname, &ofd)) != CL_SUCCESS) {
|
||||||
cli_errmsg("scan_mso_stream: Can't generate temporary file\n");
|
cli_errmsg("scan_mso_stream: Can't generate temporary file\n");
|
||||||
funmap(input);
|
fmap_free(input);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1815,7 +1815,7 @@ mso_end:
|
||||||
if (cli_unlink(tmpname))
|
if (cli_unlink(tmpname))
|
||||||
ret = CL_EUNLINK;
|
ret = CL_EUNLINK;
|
||||||
free(tmpname);
|
free(tmpname);
|
||||||
funmap(input);
|
fmap_free(input);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1841,7 +1841,7 @@ static cl_error_t handler_otf(ole2_header_t *hdr, property_t *prop, const char *
|
||||||
}
|
}
|
||||||
print_ole2_property(prop);
|
print_ole2_property(prop);
|
||||||
|
|
||||||
if (!(tempfile = cli_gentemp(ctx->sub_tmpdir))) {
|
if (!(tempfile = cli_gentemp(ctx->this_layer_tmpdir))) {
|
||||||
ret = CL_EMEM;
|
ret = CL_EMEM;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
@ -1927,7 +1927,7 @@ static cl_error_t handler_otf(ole2_header_t *hdr, property_t *prop, const char *
|
||||||
}
|
}
|
||||||
|
|
||||||
/* JSON Output Summary Information */
|
/* JSON Output Summary Information */
|
||||||
if (SCAN_COLLECT_METADATA && (ctx->properties != NULL)) {
|
if (SCAN_COLLECT_METADATA && (ctx->metadata_json != NULL)) {
|
||||||
if (!name) {
|
if (!name) {
|
||||||
name = cli_ole2_get_property_name2(prop->name, prop->name_size);
|
name = cli_ole2_get_property_name2(prop->name, prop->name_size);
|
||||||
}
|
}
|
||||||
|
@ -1935,7 +1935,7 @@ static cl_error_t handler_otf(ole2_header_t *hdr, property_t *prop, const char *
|
||||||
if (!strncmp(name, "_5_summaryinformation", 21)) {
|
if (!strncmp(name, "_5_summaryinformation", 21)) {
|
||||||
cli_dbgmsg("OLE2: detected a '_5_summaryinformation' stream\n");
|
cli_dbgmsg("OLE2: detected a '_5_summaryinformation' stream\n");
|
||||||
/* JSONOLE2 - what to do if something breaks? */
|
/* JSONOLE2 - what to do if something breaks? */
|
||||||
if (cli_ole2_summary_json(ctx, ofd, 0) == CL_ETIMEOUT) {
|
if (cli_ole2_summary_json(ctx, ofd, 0, tempfile) == CL_ETIMEOUT) {
|
||||||
ret = CL_ETIMEOUT;
|
ret = CL_ETIMEOUT;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
@ -1944,7 +1944,7 @@ static cl_error_t handler_otf(ole2_header_t *hdr, property_t *prop, const char *
|
||||||
if (!strncmp(name, "_5_documentsummaryinformation", 29)) {
|
if (!strncmp(name, "_5_documentsummaryinformation", 29)) {
|
||||||
cli_dbgmsg("OLE2: detected a '_5_documentsummaryinformation' stream\n");
|
cli_dbgmsg("OLE2: detected a '_5_documentsummaryinformation' stream\n");
|
||||||
/* JSONOLE2 - what to do if something breaks? */
|
/* JSONOLE2 - what to do if something breaks? */
|
||||||
if (cli_ole2_summary_json(ctx, ofd, 1) == CL_ETIMEOUT) {
|
if (cli_ole2_summary_json(ctx, ofd, 1, tempfile) == CL_ETIMEOUT) {
|
||||||
ret = CL_ETIMEOUT;
|
ret = CL_ETIMEOUT;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
@ -1961,7 +1961,7 @@ static cl_error_t handler_otf(ole2_header_t *hdr, property_t *prop, const char *
|
||||||
ret = CL_ESEEK;
|
ret = CL_ESEEK;
|
||||||
} else if (is_mso) {
|
} else if (is_mso) {
|
||||||
/* MSO Stream Scan */
|
/* MSO Stream Scan */
|
||||||
ret = scan_mso_stream(ofd, ctx);
|
ret = scan_mso_stream(ofd, tempfile, ctx);
|
||||||
} else {
|
} else {
|
||||||
/* Normal File Scan */
|
/* Normal File Scan */
|
||||||
ret = cli_magic_scan_desc(ofd, tempfile, ctx, NULL, LAYER_ATTRIBUTES_NONE);
|
ret = cli_magic_scan_desc(ofd, tempfile, ctx, NULL, LAYER_ATTRIBUTES_NONE);
|
||||||
|
@ -2045,7 +2045,7 @@ static cl_error_t handler_otf_encrypted(ole2_header_t *hdr, property_t *prop, co
|
||||||
|
|
||||||
nrounds = rijndaelSetupDecrypt(rk, key->key, key->key_length_bits);
|
nrounds = rijndaelSetupDecrypt(rk, key->key, key->key_length_bits);
|
||||||
|
|
||||||
if (!(tempfile = cli_gentemp(ctx->sub_tmpdir))) {
|
if (!(tempfile = cli_gentemp(ctx->this_layer_tmpdir))) {
|
||||||
ret = CL_EMEM;
|
ret = CL_EMEM;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
@ -2167,7 +2167,7 @@ static cl_error_t handler_otf_encrypted(ole2_header_t *hdr, property_t *prop, co
|
||||||
}
|
}
|
||||||
|
|
||||||
/* JSON Output Summary Information */
|
/* JSON Output Summary Information */
|
||||||
if (SCAN_COLLECT_METADATA && (ctx->properties != NULL)) {
|
if (SCAN_COLLECT_METADATA && (ctx->metadata_json != NULL)) {
|
||||||
if (!name) {
|
if (!name) {
|
||||||
name = cli_ole2_get_property_name2(prop->name, prop->name_size);
|
name = cli_ole2_get_property_name2(prop->name, prop->name_size);
|
||||||
}
|
}
|
||||||
|
@ -2175,7 +2175,7 @@ static cl_error_t handler_otf_encrypted(ole2_header_t *hdr, property_t *prop, co
|
||||||
if (!strncmp(name, "_5_summaryinformation", 21)) {
|
if (!strncmp(name, "_5_summaryinformation", 21)) {
|
||||||
cli_dbgmsg("OLE2: detected a '_5_summaryinformation' stream\n");
|
cli_dbgmsg("OLE2: detected a '_5_summaryinformation' stream\n");
|
||||||
/* JSONOLE2 - what to do if something breaks? */
|
/* JSONOLE2 - what to do if something breaks? */
|
||||||
if (cli_ole2_summary_json(ctx, ofd, 0) == CL_ETIMEOUT) {
|
if (cli_ole2_summary_json(ctx, ofd, 0, tempfile) == CL_ETIMEOUT) {
|
||||||
ret = CL_ETIMEOUT;
|
ret = CL_ETIMEOUT;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
@ -2184,7 +2184,7 @@ static cl_error_t handler_otf_encrypted(ole2_header_t *hdr, property_t *prop, co
|
||||||
if (!strncmp(name, "_5_documentsummaryinformation", 29)) {
|
if (!strncmp(name, "_5_documentsummaryinformation", 29)) {
|
||||||
cli_dbgmsg("OLE2: detected a '_5_documentsummaryinformation' stream\n");
|
cli_dbgmsg("OLE2: detected a '_5_documentsummaryinformation' stream\n");
|
||||||
/* JSONOLE2 - what to do if something breaks? */
|
/* JSONOLE2 - what to do if something breaks? */
|
||||||
if (cli_ole2_summary_json(ctx, ofd, 1) == CL_ETIMEOUT) {
|
if (cli_ole2_summary_json(ctx, ofd, 1, tempfile) == CL_ETIMEOUT) {
|
||||||
ret = CL_ETIMEOUT;
|
ret = CL_ETIMEOUT;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
@ -2201,7 +2201,7 @@ static cl_error_t handler_otf_encrypted(ole2_header_t *hdr, property_t *prop, co
|
||||||
ret = CL_ESEEK;
|
ret = CL_ESEEK;
|
||||||
} else if (is_mso) {
|
} else if (is_mso) {
|
||||||
/* MSO Stream Scan */
|
/* MSO Stream Scan */
|
||||||
ret = scan_mso_stream(ofd, ctx);
|
ret = scan_mso_stream(ofd, tempfile, ctx);
|
||||||
} else {
|
} else {
|
||||||
/* Normal File Scan */
|
/* Normal File Scan */
|
||||||
ret = cli_magic_scan_desc(ofd, tempfile, ctx, NULL, LAYER_ATTRIBUTES_NONE);
|
ret = cli_magic_scan_desc(ofd, tempfile, ctx, NULL, LAYER_ATTRIBUTES_NONE);
|
||||||
|
@ -2939,12 +2939,12 @@ cl_error_t cli_ole2_extract(const char *dirname, cli_ctx *ctx, struct uniq **fil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (SCAN_COLLECT_METADATA && (ctx->wrkproperty != NULL)) {
|
if (SCAN_COLLECT_METADATA && (ctx->this_layer_metadata_json != NULL)) {
|
||||||
if (encryption_status.encrypted) {
|
if (encryption_status.encrypted) {
|
||||||
if (encryption_status.encryption_type) {
|
if (encryption_status.encryption_type) {
|
||||||
cli_jsonstr(ctx->wrkproperty, ENCRYPTED_JSON_KEY, encryption_status.encryption_type);
|
cli_jsonstr(ctx->this_layer_metadata_json, ENCRYPTED_JSON_KEY, encryption_status.encryption_type);
|
||||||
} else {
|
} else {
|
||||||
cli_jsonstr(ctx->wrkproperty, ENCRYPTED_JSON_KEY, GENERIC_ENCRYPTED);
|
cli_jsonstr(ctx->this_layer_metadata_json, ENCRYPTED_JSON_KEY, GENERIC_ENCRYPTED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -151,9 +151,9 @@ static cl_error_t ooxml_core_cb(int fd, const char *filepath, cli_ctx *ctx, cons
|
||||||
cli_dbgmsg("in ooxml_core_cb\n");
|
cli_dbgmsg("in ooxml_core_cb\n");
|
||||||
ret = ooxml_parse_document(fd, ctx);
|
ret = ooxml_parse_document(fd, ctx);
|
||||||
if (ret == CL_EPARSE)
|
if (ret == CL_EPARSE)
|
||||||
cli_json_parse_error(ctx->wrkproperty, "OOXML_ERROR_CORE_XMLPARSER");
|
cli_json_parse_error(ctx->this_layer_metadata_json, "OOXML_ERROR_CORE_XMLPARSER");
|
||||||
else if (ret == CL_EFORMAT)
|
else if (ret == CL_EFORMAT)
|
||||||
cli_json_parse_error(ctx->wrkproperty, "OOXML_ERROR_CORE_MALFORMED");
|
cli_json_parse_error(ctx->this_layer_metadata_json, "OOXML_ERROR_CORE_MALFORMED");
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -169,9 +169,9 @@ static cl_error_t ooxml_extn_cb(int fd, const char *filepath, cli_ctx *ctx, cons
|
||||||
cli_dbgmsg("in ooxml_extn_cb\n");
|
cli_dbgmsg("in ooxml_extn_cb\n");
|
||||||
ret = ooxml_parse_document(fd, ctx);
|
ret = ooxml_parse_document(fd, ctx);
|
||||||
if (ret == CL_EPARSE)
|
if (ret == CL_EPARSE)
|
||||||
cli_json_parse_error(ctx->wrkproperty, "OOXML_ERROR_EXTN_XMLPARSER");
|
cli_json_parse_error(ctx->this_layer_metadata_json, "OOXML_ERROR_EXTN_XMLPARSER");
|
||||||
else if (ret == CL_EFORMAT)
|
else if (ret == CL_EFORMAT)
|
||||||
cli_json_parse_error(ctx->wrkproperty, "OOXML_ERROR_EXTN_MALFORMED");
|
cli_json_parse_error(ctx->this_layer_metadata_json, "OOXML_ERROR_EXTN_MALFORMED");
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -206,7 +206,7 @@ static cl_error_t ooxml_content_cb(int fd, const char *filepath, cli_ctx *ctx, c
|
||||||
cli_dbgmsg("ooxml_content_cb: xmlReaderForFd error for "
|
cli_dbgmsg("ooxml_content_cb: xmlReaderForFd error for "
|
||||||
"[Content_Types].xml"
|
"[Content_Types].xml"
|
||||||
"\n");
|
"\n");
|
||||||
cli_json_parse_error(ctx->wrkproperty, "OOXML_ERROR_XML_READER_FD");
|
cli_json_parse_error(ctx->this_layer_metadata_json, "OOXML_ERROR_XML_READER_FD");
|
||||||
|
|
||||||
ctx->scansize = sav_scansize;
|
ctx->scansize = sav_scansize;
|
||||||
ctx->scannedfiles = sav_scannedfiles;
|
ctx->scannedfiles = sav_scannedfiles;
|
||||||
|
@ -303,40 +303,40 @@ static cl_error_t ooxml_content_cb(int fd, const char *filepath, cli_ctx *ctx, c
|
||||||
|
|
||||||
ooxml_content_exit:
|
ooxml_content_exit:
|
||||||
if (core) {
|
if (core) {
|
||||||
cli_jsonint(ctx->wrkproperty, "CorePropertiesFileCount", core);
|
cli_jsonint(ctx->this_layer_metadata_json, "CorePropertiesFileCount", core);
|
||||||
if (core > 1)
|
if (core > 1)
|
||||||
cli_json_parse_error(ctx->wrkproperty, "OOXML_ERROR_MULTIPLE_CORE_PROPFILES");
|
cli_json_parse_error(ctx->this_layer_metadata_json, "OOXML_ERROR_MULTIPLE_CORE_PROPFILES");
|
||||||
} else if (!mcore)
|
} else if (!mcore)
|
||||||
cli_dbgmsg("cli_process_ooxml: file does not contain core properties file\n");
|
cli_dbgmsg("cli_process_ooxml: file does not contain core properties file\n");
|
||||||
if (mcore) {
|
if (mcore) {
|
||||||
cli_jsonint(ctx->wrkproperty, "CorePropertiesMissingFileCount", mcore);
|
cli_jsonint(ctx->this_layer_metadata_json, "CorePropertiesMissingFileCount", mcore);
|
||||||
cli_json_parse_error(ctx->wrkproperty, "OOXML_ERROR_MISSING_CORE_PROPFILES");
|
cli_json_parse_error(ctx->this_layer_metadata_json, "OOXML_ERROR_MISSING_CORE_PROPFILES");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (extn) {
|
if (extn) {
|
||||||
cli_jsonint(ctx->wrkproperty, "ExtendedPropertiesFileCount", extn);
|
cli_jsonint(ctx->this_layer_metadata_json, "ExtendedPropertiesFileCount", extn);
|
||||||
if (extn > 1)
|
if (extn > 1)
|
||||||
cli_json_parse_error(ctx->wrkproperty, "OOXML_ERROR_MULTIPLE_EXTN_PROPFILES");
|
cli_json_parse_error(ctx->this_layer_metadata_json, "OOXML_ERROR_MULTIPLE_EXTN_PROPFILES");
|
||||||
} else if (!mextn)
|
} else if (!mextn)
|
||||||
cli_dbgmsg("cli_process_ooxml: file does not contain extended properties file\n");
|
cli_dbgmsg("cli_process_ooxml: file does not contain extended properties file\n");
|
||||||
if (mextn) {
|
if (mextn) {
|
||||||
cli_jsonint(ctx->wrkproperty, "ExtendedPropertiesMissingFileCount", mextn);
|
cli_jsonint(ctx->this_layer_metadata_json, "ExtendedPropertiesMissingFileCount", mextn);
|
||||||
cli_json_parse_error(ctx->wrkproperty, "OOXML_ERROR_MISSING_EXTN_PROPFILES");
|
cli_json_parse_error(ctx->this_layer_metadata_json, "OOXML_ERROR_MISSING_EXTN_PROPFILES");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cust) {
|
if (cust) {
|
||||||
cli_jsonint(ctx->wrkproperty, "CustomPropertiesFileCount", cust);
|
cli_jsonint(ctx->this_layer_metadata_json, "CustomPropertiesFileCount", cust);
|
||||||
if (cust > 1)
|
if (cust > 1)
|
||||||
cli_json_parse_error(ctx->wrkproperty, "OOXML_ERROR_MULTIPLE_CUSTOM_PROPFILES");
|
cli_json_parse_error(ctx->this_layer_metadata_json, "OOXML_ERROR_MULTIPLE_CUSTOM_PROPFILES");
|
||||||
} else if (!mcust)
|
} else if (!mcust)
|
||||||
cli_dbgmsg("cli_process_ooxml: file does not contain custom properties file\n");
|
cli_dbgmsg("cli_process_ooxml: file does not contain custom properties file\n");
|
||||||
if (mcust) {
|
if (mcust) {
|
||||||
cli_jsonint(ctx->wrkproperty, "CustomPropertiesMissingFileCount", mcust);
|
cli_jsonint(ctx->this_layer_metadata_json, "CustomPropertiesMissingFileCount", mcust);
|
||||||
cli_json_parse_error(ctx->wrkproperty, "OOXML_ERROR_MISSING_CUST_PROPFILES");
|
cli_json_parse_error(ctx->this_layer_metadata_json, "OOXML_ERROR_MISSING_CUST_PROPFILES");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dsig) {
|
if (dsig) {
|
||||||
cli_jsonint(ctx->wrkproperty, "DigitalSignaturesCount", dsig);
|
cli_jsonint(ctx->this_layer_metadata_json, "DigitalSignaturesCount", dsig);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* restore the engine tracking limits; resets session limit tracking */
|
/* restore the engine tracking limits; resets session limit tracking */
|
||||||
|
@ -380,7 +380,7 @@ static cl_error_t ooxml_hwp_cb(int fd, const char *filepath, cli_ctx *ctx, const
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
cli_file_t cli_ooxml_filetype(cli_ctx *ctx, fmap_t *map)
|
cli_file_t cli_ooxml_filetype(cli_ctx *ctx)
|
||||||
{
|
{
|
||||||
struct zip_requests requests;
|
struct zip_requests requests;
|
||||||
cl_error_t ret;
|
cl_error_t ret;
|
||||||
|
@ -400,7 +400,7 @@ cli_file_t cli_ooxml_filetype(cli_ctx *ctx, fmap_t *map)
|
||||||
return CL_TYPE_ANY;
|
return CL_TYPE_ANY;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((ret = unzip_search(ctx, map, &requests)) == CL_VIRUS) {
|
if ((ret = unzip_search(ctx, &requests)) == CL_VIRUS) {
|
||||||
switch (requests.found) {
|
switch (requests.found) {
|
||||||
case 0:
|
case 0:
|
||||||
return CL_TYPE_OOXML_XL;
|
return CL_TYPE_OOXML_XL;
|
||||||
|
@ -437,7 +437,7 @@ cl_error_t cli_process_ooxml(cli_ctx *ctx, int type)
|
||||||
cli_dbgmsg("cli_process_ooxml: failed to find "
|
cli_dbgmsg("cli_process_ooxml: failed to find "
|
||||||
"version.xml"
|
"version.xml"
|
||||||
"!\n");
|
"!\n");
|
||||||
cli_json_parse_error(ctx->wrkproperty, "OOXML_ERROR_NO_HWP_VERSION");
|
cli_json_parse_error(ctx->this_layer_metadata_json, "OOXML_ERROR_NO_HWP_VERSION");
|
||||||
return CL_EFORMAT;
|
return CL_EFORMAT;
|
||||||
}
|
}
|
||||||
ret = unzip_single_internal(ctx, loff, ooxml_hwp_cb);
|
ret = unzip_single_internal(ctx, loff, ooxml_hwp_cb);
|
||||||
|
@ -450,7 +450,7 @@ cl_error_t cli_process_ooxml(cli_ctx *ctx, int type)
|
||||||
cli_dbgmsg("cli_process_ooxml: failed to find "
|
cli_dbgmsg("cli_process_ooxml: failed to find "
|
||||||
"Contents/content.hpf"
|
"Contents/content.hpf"
|
||||||
"!\n");
|
"!\n");
|
||||||
cli_json_parse_error(ctx->wrkproperty, "OOXML_ERROR_NO_HWP_CONTENT");
|
cli_json_parse_error(ctx->this_layer_metadata_json, "OOXML_ERROR_NO_HWP_CONTENT");
|
||||||
return CL_EFORMAT;
|
return CL_EFORMAT;
|
||||||
}
|
}
|
||||||
ret = unzip_single_internal(ctx, loff, ooxml_hwp_cb);
|
ret = unzip_single_internal(ctx, loff, ooxml_hwp_cb);
|
||||||
|
@ -464,7 +464,7 @@ cl_error_t cli_process_ooxml(cli_ctx *ctx, int type)
|
||||||
cli_dbgmsg("cli_process_ooxml: failed to find "
|
cli_dbgmsg("cli_process_ooxml: failed to find "
|
||||||
"[Content_Types].xml"
|
"[Content_Types].xml"
|
||||||
"!\n");
|
"!\n");
|
||||||
cli_json_parse_error(ctx->wrkproperty, "OOXML_ERROR_NO_CONTENT_TYPES");
|
cli_json_parse_error(ctx->this_layer_metadata_json, "OOXML_ERROR_NO_CONTENT_TYPES");
|
||||||
return CL_EFORMAT;
|
return CL_EFORMAT;
|
||||||
}
|
}
|
||||||
cli_dbgmsg("cli_process_ooxml: found "
|
cli_dbgmsg("cli_process_ooxml: found "
|
||||||
|
|
|
@ -27,7 +27,7 @@
|
||||||
|
|
||||||
#include "others.h"
|
#include "others.h"
|
||||||
|
|
||||||
cli_file_t cli_ooxml_filetype(cli_ctx *, fmap_t *);
|
cli_file_t cli_ooxml_filetype(cli_ctx *);
|
||||||
cl_error_t cli_process_ooxml(cli_ctx *, int);
|
cl_error_t cli_process_ooxml(cli_ctx *, int);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -37,7 +37,7 @@
|
||||||
#include <libxml/xmlreader.h>
|
#include <libxml/xmlreader.h>
|
||||||
|
|
||||||
struct openioc_hash {
|
struct openioc_hash {
|
||||||
unsigned char *hash;
|
uint8_t *hash;
|
||||||
void *next;
|
void *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -311,7 +311,7 @@ int openioc_parse(const char *fname, int fd, struct cl_engine *engine, unsigned
|
||||||
|
|
||||||
free(vp);
|
free(vp);
|
||||||
|
|
||||||
rc = hm_addhash_str(engine->hm_hdb, hash, 0, virusname);
|
rc = hm_addhash_str(engine, HASH_PURPOSE_WHOLE_FILE_DETECT, hash, 0, virusname);
|
||||||
if (rc != CL_SUCCESS)
|
if (rc != CL_SUCCESS)
|
||||||
cli_dbgmsg("openioc_parse: hm_addhash_str failed with %i hash len %i for %s.\n",
|
cli_dbgmsg("openioc_parse: hm_addhash_str failed with %i hash len %i for %s.\n",
|
||||||
rc, hashlen, virusname);
|
rc, hashlen, virusname);
|
||||||
|
|
35
libclamav/other_types.h
Normal file
35
libclamav/other_types.h
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
* Copyright (C) 2021-2025 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
|
||||||
|
*
|
||||||
|
* Authors: Valerie Snyder
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License version 2 as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||||
|
* MA 02110-1301, USA.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __OTHER_TYPES_H_LC
|
||||||
|
#define __OTHER_TYPES_H_LC
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
typedef struct image_fuzzy_hash {
|
||||||
|
uint8_t hash[8];
|
||||||
|
} image_fuzzy_hash_t;
|
||||||
|
|
||||||
|
typedef void *evidence_t;
|
||||||
|
typedef void *onedump_t;
|
||||||
|
typedef void *cvd_t;
|
||||||
|
typedef void *cli_ctx_t;
|
||||||
|
|
||||||
|
#endif /* __OTHER_TYPES_H_LC */
|
1207
libclamav/others.c
1207
libclamav/others.c
File diff suppressed because it is too large
Load diff
|
@ -43,6 +43,7 @@
|
||||||
#include <json.h>
|
#include <json.h>
|
||||||
|
|
||||||
#include "clamav.h"
|
#include "clamav.h"
|
||||||
|
#include "other_types.h"
|
||||||
#include "dconf.h"
|
#include "dconf.h"
|
||||||
#include "filetypes.h"
|
#include "filetypes.h"
|
||||||
#include "fmap.h"
|
#include "fmap.h"
|
||||||
|
@ -51,6 +52,7 @@
|
||||||
#include "bytecode_api.h"
|
#include "bytecode_api.h"
|
||||||
#include "events.h"
|
#include "events.h"
|
||||||
#include "crtmgr.h"
|
#include "crtmgr.h"
|
||||||
|
#include "scan_layer.h"
|
||||||
|
|
||||||
#include "unrar_iface.h"
|
#include "unrar_iface.h"
|
||||||
|
|
||||||
|
@ -171,52 +173,29 @@ typedef struct bitset_tag {
|
||||||
unsigned long length;
|
unsigned long length;
|
||||||
} bitset_t;
|
} bitset_t;
|
||||||
|
|
||||||
typedef struct image_fuzzy_hash {
|
|
||||||
uint8_t hash[8];
|
|
||||||
} image_fuzzy_hash_t;
|
|
||||||
|
|
||||||
typedef struct recursion_level_tag {
|
|
||||||
cli_file_t type;
|
|
||||||
size_t size;
|
|
||||||
cl_fmap_t *fmap; /* The fmap for this layer. This used to be in an array in the ctx. */
|
|
||||||
uint32_t recursion_level_buffer; /* Which buffer layer in scan recursion. */
|
|
||||||
uint32_t recursion_level_buffer_fmap; /* Which fmap layer in this buffer. */
|
|
||||||
uint32_t attributes; /* layer attributes. */
|
|
||||||
image_fuzzy_hash_t image_fuzzy_hash; /* Used for image/graphics files to store a fuzzy hash. */
|
|
||||||
bool calculated_image_fuzzy_hash; /* Used for image/graphics files to store a fuzzy hash. */
|
|
||||||
} recursion_level_t;
|
|
||||||
|
|
||||||
typedef void *evidence_t;
|
|
||||||
typedef void *onedump_t;
|
|
||||||
typedef void *cvd_t;
|
|
||||||
|
|
||||||
/* internal clamav context */
|
/* internal clamav context */
|
||||||
typedef struct cli_ctx_tag {
|
typedef struct cli_ctx_tag {
|
||||||
char *target_filepath; /* (optional) The filepath of the original scan target. */
|
char *target_filepath; /* (optional) The filepath of the original scan target. */
|
||||||
const char *sub_filepath; /* (optional) The filepath of the current file being parsed. May be a temp file. */
|
char *this_layer_tmpdir; /* Pointer to current temporary directory, MAY vary with recursion depth. For convenience. */
|
||||||
char *sub_tmpdir; /* The directory to store tmp files at this recursion depth. */
|
uint64_t *scanned;
|
||||||
evidence_t evidence; /* Stores the evidence for this scan to alert (alerting indicators). */
|
|
||||||
unsigned long int *scanned;
|
|
||||||
const struct cli_matcher *root;
|
const struct cli_matcher *root;
|
||||||
const struct cl_engine *engine;
|
const struct cl_engine *engine;
|
||||||
uint64_t scansize;
|
uint64_t scansize;
|
||||||
struct cl_scan_options *options;
|
struct cl_scan_options *options;
|
||||||
unsigned int scannedfiles;
|
uint32_t scannedfiles;
|
||||||
unsigned int corrupted_input; /* Setting this flag will prevent the PE parser from reporting "broken executable" for unpacked/reconstructed files that may not be 100% to spec. */
|
unsigned int corrupted_input; /* Setting this flag will prevent the PE parser from reporting "broken executable" for unpacked/reconstructed files that may not be 100% to spec. */
|
||||||
recursion_level_t *recursion_stack; /* Array of recursion levels used as a stack. */
|
cli_scan_layer_t *recursion_stack; /* Array of recursion levels used as a stack. */
|
||||||
uint32_t recursion_stack_size; /* stack size must == engine->max_recursion_level */
|
uint32_t recursion_stack_size; /* stack size must == engine->max_recursion_level */
|
||||||
uint32_t recursion_level; /* Index into recursion_stack; current fmap recursion level from start of scan. */
|
uint32_t recursion_level; /* Index into recursion_stack; current fmap recursion level from start of scan. */
|
||||||
fmap_t *fmap; /* Pointer to current fmap in recursion_stack, varies with recursion depth. For convenience. */
|
evidence_t this_layer_evidence; /* Pointer to current evidence in recursion_stack, varies with recursion depth. For convenience. */
|
||||||
unsigned char handlertype_hash[16];
|
fmap_t *fmap; /* Pointer to current fmap in recursion_stack, varies with recursion depth. For convenience. */
|
||||||
|
size_t object_count; /* Counter for number of unique entities/contained files (including normalized files) processed. */
|
||||||
struct cli_dconf *dconf;
|
struct cli_dconf *dconf;
|
||||||
bitset_t *hook_lsig_matches;
|
bitset_t *hook_lsig_matches;
|
||||||
void *cb_ctx;
|
void *cb_ctx;
|
||||||
cli_events_t *perf;
|
cli_events_t *perf;
|
||||||
#ifdef HAVE__INTERNAL__SHA_COLLECT
|
struct json_object *metadata_json; /* Top level metadata JSON object for the whole scan. */
|
||||||
int sha_collect;
|
struct json_object *this_layer_metadata_json; /* Pointer to current metadata JSON object in recursion_stack, varies with recursion depth. For convenience. */
|
||||||
#endif
|
|
||||||
struct json_object *properties;
|
|
||||||
struct json_object *wrkproperty;
|
|
||||||
struct timeval time_limit;
|
struct timeval time_limit;
|
||||||
bool limit_exceeded; /* To guard against alerting on limits exceeded more than once, or storing that in the JSON metadata more than once. */
|
bool limit_exceeded; /* To guard against alerting on limits exceeded more than once, or storing that in the JSON metadata more than once. */
|
||||||
bool abort_scan; /* So we can guarantee a scan is aborted, even if CL_ETIMEOUT/etc. status is lost in the scan recursion stack. */
|
bool abort_scan; /* So we can guarantee a scan is aborted, even if CL_ETIMEOUT/etc. status is lost in the scan recursion stack. */
|
||||||
|
@ -228,7 +207,7 @@ typedef struct cli_ctx_tag {
|
||||||
|
|
||||||
typedef struct cli_flagged_sample {
|
typedef struct cli_flagged_sample {
|
||||||
char **virus_name;
|
char **virus_name;
|
||||||
char md5[16];
|
char md5[MD5_HASH_SIZE];
|
||||||
uint32_t size; /* A size of zero means size is unavailable (why would this ever happen?) */
|
uint32_t size; /* A size of zero means size is unavailable (why would this ever happen?) */
|
||||||
uint32_t hits;
|
uint32_t hits;
|
||||||
stats_section_t *sections;
|
stats_section_t *sections;
|
||||||
|
@ -405,8 +384,13 @@ struct cl_engine {
|
||||||
crtmgr cmgr;
|
crtmgr cmgr;
|
||||||
|
|
||||||
/* Callback(s) */
|
/* Callback(s) */
|
||||||
clcb_file_inspection cb_file_inspection;
|
clcb_scan cb_scan_pre_hash;
|
||||||
|
clcb_scan cb_scan_pre_scan;
|
||||||
|
clcb_scan cb_scan_post_scan;
|
||||||
|
clcb_scan cb_scan_alert;
|
||||||
|
clcb_scan cb_scan_file_type;
|
||||||
clcb_pre_cache cb_pre_cache;
|
clcb_pre_cache cb_pre_cache;
|
||||||
|
clcb_file_inspection cb_file_inspection;
|
||||||
clcb_pre_scan cb_pre_scan;
|
clcb_pre_scan cb_pre_scan;
|
||||||
clcb_post_scan cb_post_scan;
|
clcb_post_scan cb_post_scan;
|
||||||
clcb_virus_found cb_virus_found;
|
clcb_virus_found cb_virus_found;
|
||||||
|
@ -556,6 +540,7 @@ extern LIBCLAMAV_EXPORT int have_rar;
|
||||||
#define SCAN_UNPRIVILEGED (ctx->options->general & CL_SCAN_GENERAL_UNPRIVILEGED)
|
#define SCAN_UNPRIVILEGED (ctx->options->general & CL_SCAN_GENERAL_UNPRIVILEGED)
|
||||||
#define SCAN_STORE_HTML_URIS (ctx->options->general & CL_SCAN_GENERAL_STORE_HTML_URIS)
|
#define SCAN_STORE_HTML_URIS (ctx->options->general & CL_SCAN_GENERAL_STORE_HTML_URIS)
|
||||||
#define SCAN_STORE_PDF_URIS (ctx->options->general & CL_SCAN_GENERAL_STORE_PDF_URIS)
|
#define SCAN_STORE_PDF_URIS (ctx->options->general & CL_SCAN_GENERAL_STORE_PDF_URIS)
|
||||||
|
#define SCAN_STORE_EXTRA_HASHES (ctx->options->general & CL_SCAN_GENERAL_STORE_EXTRA_HASHES)
|
||||||
|
|
||||||
#define SCAN_PARSE_ARCHIVE (ctx->options->parse & CL_SCAN_PARSE_ARCHIVE)
|
#define SCAN_PARSE_ARCHIVE (ctx->options->parse & CL_SCAN_PARSE_ARCHIVE)
|
||||||
#define SCAN_PARSE_ELF (ctx->options->parse & CL_SCAN_PARSE_ELF)
|
#define SCAN_PARSE_ELF (ctx->options->parse & CL_SCAN_PARSE_ELF)
|
||||||
|
@ -586,21 +571,20 @@ extern LIBCLAMAV_EXPORT int have_rar;
|
||||||
|
|
||||||
#define SCAN_MAIL_PARTIAL_MESSAGE (ctx->options->mail & CL_SCAN_MAIL_PARTIAL_MESSAGE)
|
#define SCAN_MAIL_PARTIAL_MESSAGE (ctx->options->mail & CL_SCAN_MAIL_PARTIAL_MESSAGE)
|
||||||
|
|
||||||
#define SCAN_DEV_COLLECT_SHA (ctx->options->dev & CL_SCAN_DEV_COLLECT_SHA)
|
|
||||||
#define SCAN_DEV_COLLECT_PERF_INFO (ctx->options->dev & CL_SCAN_DEV_COLLECT_PERFORMANCE_INFO)
|
#define SCAN_DEV_COLLECT_PERF_INFO (ctx->options->dev & CL_SCAN_DEV_COLLECT_PERFORMANCE_INFO)
|
||||||
|
|
||||||
/* based on macros from A. Melnikoff */
|
/* based on macros from A. Melnikoff */
|
||||||
#define cbswap16(v) (((v & 0xff) << 8) | (((v) >> 8) & 0xff))
|
#define cbswap16(v) (((v & 0xff) << 8) | (((v) >> 8) & 0xff))
|
||||||
#define cbswap32(v) ((((v)&0x000000ff) << 24) | (((v)&0x0000ff00) << 8) | \
|
#define cbswap32(v) ((((v) & 0x000000ff) << 24) | (((v) & 0x0000ff00) << 8) | \
|
||||||
(((v)&0x00ff0000) >> 8) | (((v)&0xff000000) >> 24))
|
(((v) & 0x00ff0000) >> 8) | (((v) & 0xff000000) >> 24))
|
||||||
#define cbswap64(v) ((((v)&0x00000000000000ffULL) << 56) | \
|
#define cbswap64(v) ((((v) & 0x00000000000000ffULL) << 56) | \
|
||||||
(((v)&0x000000000000ff00ULL) << 40) | \
|
(((v) & 0x000000000000ff00ULL) << 40) | \
|
||||||
(((v)&0x0000000000ff0000ULL) << 24) | \
|
(((v) & 0x0000000000ff0000ULL) << 24) | \
|
||||||
(((v)&0x00000000ff000000ULL) << 8) | \
|
(((v) & 0x00000000ff000000ULL) << 8) | \
|
||||||
(((v)&0x000000ff00000000ULL) >> 8) | \
|
(((v) & 0x000000ff00000000ULL) >> 8) | \
|
||||||
(((v)&0x0000ff0000000000ULL) >> 24) | \
|
(((v) & 0x0000ff0000000000ULL) >> 24) | \
|
||||||
(((v)&0x00ff000000000000ULL) >> 40) | \
|
(((v) & 0x00ff000000000000ULL) >> 40) | \
|
||||||
(((v)&0xff00000000000000ULL) >> 56))
|
(((v) & 0xff00000000000000ULL) >> 56))
|
||||||
|
|
||||||
#ifndef HAVE_ATTRIB_PACKED
|
#ifndef HAVE_ATTRIB_PACKED
|
||||||
#define __attribute__(x)
|
#define __attribute__(x)
|
||||||
|
@ -751,7 +735,18 @@ void cli_append_potentially_unwanted_if_heur_exceedsmax(cli_ctx *ctx, char *virn
|
||||||
|
|
||||||
const char *cli_get_last_virus(const cli_ctx *ctx);
|
const char *cli_get_last_virus(const cli_ctx *ctx);
|
||||||
const char *cli_get_last_virus_str(const cli_ctx *ctx);
|
const char *cli_get_last_virus_str(const cli_ctx *ctx);
|
||||||
void cli_virus_found_cb(cli_ctx *ctx, const char *virname);
|
|
||||||
|
/**
|
||||||
|
* @brief Dispatch the alert / virus found callbacks.
|
||||||
|
*
|
||||||
|
* AKA for clamscan it will print FOUND message.
|
||||||
|
*
|
||||||
|
* @param ctx The scan context.
|
||||||
|
* @param virname The name of the virus.
|
||||||
|
* @param is_potentially_unwanted true if the alert is for a potentially unwanted application (PUA).
|
||||||
|
* @return cl_error_t
|
||||||
|
*/
|
||||||
|
cl_error_t cli_virus_found_cb(cli_ctx *ctx, const char *virname, bool is_potentially_unwanted);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Push a new fmap onto our scan recursion stack.
|
* @brief Push a new fmap onto our scan recursion stack.
|
||||||
|
@ -770,7 +765,7 @@ cl_error_t cli_recursion_stack_push(cli_ctx *ctx, cl_fmap_t *map, cli_file_t typ
|
||||||
/**
|
/**
|
||||||
* @brief Pop off a layer of our scan recursion stack.
|
* @brief Pop off a layer of our scan recursion stack.
|
||||||
*
|
*
|
||||||
* Returns the fmap for the popped layer. Does NOT funmap() the fmap for you.
|
* Returns the fmap for the popped layer. Does NOT fmap_free() the fmap for you.
|
||||||
*
|
*
|
||||||
* @param ctx The scanning context.
|
* @param ctx The scanning context.
|
||||||
* @return cl_fmap_t* A pointer to the fmap for the popped layer, may return NULL instead if the stack is empty.
|
* @return cl_fmap_t* A pointer to the fmap for the popped layer, may return NULL instead if the stack is empty.
|
||||||
|
@ -780,10 +775,13 @@ cl_fmap_t *cli_recursion_stack_pop(cli_ctx *ctx);
|
||||||
/**
|
/**
|
||||||
* @brief Re-assign the type for the current layer.
|
* @brief Re-assign the type for the current layer.
|
||||||
*
|
*
|
||||||
* @param ctx The scanning context.
|
* @param ctx The scanning context.
|
||||||
* @param type The new file type.
|
* @param type The new file type.
|
||||||
|
* @param run_callback Whether to run the scan callback for file type corrections.
|
||||||
|
*
|
||||||
|
* @return cl_error_t CL_SUCCESS if successful, else an error code.
|
||||||
*/
|
*/
|
||||||
void cli_recursion_stack_change_type(cli_ctx *ctx, cli_file_t type);
|
cl_error_t cli_recursion_stack_change_type(cli_ctx *ctx, cli_file_t type, bool run_callback);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the type of a specific layer.
|
* @brief Get the type of a specific layer.
|
||||||
|
@ -823,11 +821,20 @@ cli_file_t cli_recursion_stack_get_type(cli_ctx *ctx, int index);
|
||||||
*/
|
*/
|
||||||
size_t cli_recursion_stack_get_size(cli_ctx *ctx, int index);
|
size_t cli_recursion_stack_get_size(cli_ctx *ctx, int index);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Dispatch scan callback based on location.
|
||||||
|
*
|
||||||
|
* @param ctx Current scan context.
|
||||||
|
* @param location Callback location.
|
||||||
|
* @return cl_error_t
|
||||||
|
*/
|
||||||
|
cl_error_t cli_dispatch_scan_callback(cli_ctx *ctx, cl_scan_callback_t location);
|
||||||
|
|
||||||
/* used by: spin, yc (C) aCaB */
|
/* used by: spin, yc (C) aCaB */
|
||||||
#define __SHIFTBITS(a) (sizeof(a) << 3)
|
#define __SHIFTBITS(a) (sizeof(a) << 3)
|
||||||
#define __SHIFTMASK(a) (__SHIFTBITS(a) - 1)
|
#define __SHIFTMASK(a) (__SHIFTBITS(a) - 1)
|
||||||
#define CLI_ROL(a, b) a = (a << ((b)&__SHIFTMASK(a))) | (a >> ((__SHIFTBITS(a) - (b)) & __SHIFTMASK(a)))
|
#define CLI_ROL(a, b) a = (a << ((b) & __SHIFTMASK(a))) | (a >> ((__SHIFTBITS(a) - (b)) & __SHIFTMASK(a)))
|
||||||
#define CLI_ROR(a, b) a = (a >> ((b)&__SHIFTMASK(a))) | (a << ((__SHIFTBITS(a) - (b)) & __SHIFTMASK(a)))
|
#define CLI_ROR(a, b) a = (a >> ((b) & __SHIFTMASK(a))) | (a << ((__SHIFTBITS(a) - (b)) & __SHIFTMASK(a)))
|
||||||
|
|
||||||
/* Implementation independent sign-extended signed right shift */
|
/* Implementation independent sign-extended signed right shift */
|
||||||
#ifdef HAVE_SAR
|
#ifdef HAVE_SAR
|
||||||
|
@ -1029,8 +1036,25 @@ void *cli_safer_realloc_or_free(void *ptr, size_t size);
|
||||||
char *cli_safer_strdup(const char *s);
|
char *cli_safer_strdup(const char *s);
|
||||||
|
|
||||||
int cli_rmdirs(const char *dirname);
|
int cli_rmdirs(const char *dirname);
|
||||||
char *cli_hashstream(FILE *fs, unsigned char *digcpy, int type);
|
|
||||||
char *cli_hashfile(const char *filename, int type);
|
/**
|
||||||
|
* @brief Calculate a hash of a stream.
|
||||||
|
* @param fs The file stream to read from.
|
||||||
|
* @param[out] hash (Optional) The buffer to store the calculated raw binary hash.
|
||||||
|
* @param type The type of hash to calculate.
|
||||||
|
* @return char* Returns the allocated hash string or NULL if allocation failed.
|
||||||
|
*/
|
||||||
|
char *cli_hashstream(FILE *fs, uint8_t *hash, cli_hash_type_t type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Calculate a hash of a file.
|
||||||
|
*
|
||||||
|
* @param filename The file to read from.
|
||||||
|
* @param[out] hash (Optional) The buffer to store the calculated raw binary hash.
|
||||||
|
* @param type The type of hash to calculate.
|
||||||
|
* @return char* Returns the allocated hash string or NULL if allocation failed.
|
||||||
|
*/
|
||||||
|
char *cli_hashfile(const char *filename, uint8_t *hash, cli_hash_type_t type);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief unlink() with error checking
|
* @brief unlink() with error checking
|
||||||
|
@ -1299,6 +1323,26 @@ uint8_t cli_get_debug_flag(void);
|
||||||
*/
|
*/
|
||||||
uint8_t cli_set_debug_flag(uint8_t debug_flag);
|
uint8_t cli_set_debug_flag(uint8_t debug_flag);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Trust the current layer by removing any evidence and setting the verdict to trusted.
|
||||||
|
*
|
||||||
|
* @param ctx The scan context.
|
||||||
|
* @param source The source of the trust request.
|
||||||
|
* @return cl_error_t CL_SUCCESS on success, or an error code.
|
||||||
|
*/
|
||||||
|
cl_error_t cli_trust_this_layer(cli_ctx *ctx, const char *source);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Trust a range of layers by removing any evidence and setting the verdict to trusted.
|
||||||
|
*
|
||||||
|
* @param ctx The scan context.
|
||||||
|
* @param start_layer The layer to start trusting from (inclusive).
|
||||||
|
* @param end_layer The layer to stop trusting at (inclusive).
|
||||||
|
* @param source The source of the trust request.
|
||||||
|
* @return cl_error_t CL_SUCCESS on success, or an error code.
|
||||||
|
*/
|
||||||
|
cl_error_t cli_trust_layers(cli_ctx *ctx, uint32_t start_layer, uint32_t end_layer, const char *source);
|
||||||
|
|
||||||
#ifndef CLI_SAFER_STRDUP_OR_GOTO_DONE
|
#ifndef CLI_SAFER_STRDUP_OR_GOTO_DONE
|
||||||
/**
|
/**
|
||||||
* @brief Wrapper around strdup that does a NULL check.
|
* @brief Wrapper around strdup that does a NULL check.
|
||||||
|
|
|
@ -1058,7 +1058,7 @@ static size_t find_length(struct pdf_struct *pdf, struct pdf_obj *obj, const cha
|
||||||
|
|
||||||
#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))
|
#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 run_pdf_hooks(struct pdf_struct *pdf, enum pdf_phase phase, int fd)
|
static int run_pdf_hooks(struct pdf_struct *pdf, enum pdf_phase phase, int fd, const char *filepath)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
struct cli_bc_ctx *bc_ctx;
|
struct cli_bc_ctx *bc_ctx;
|
||||||
|
@ -1078,7 +1078,8 @@ static int run_pdf_hooks(struct pdf_struct *pdf, enum pdf_phase phase, int fd)
|
||||||
|
|
||||||
map = ctx->fmap;
|
map = ctx->fmap;
|
||||||
if (fd != -1) {
|
if (fd != -1) {
|
||||||
map = fmap(fd, 0, 0, NULL);
|
/* The fmap in this bytecode context is an extracted pdf object. */
|
||||||
|
map = fmap_new(fd, 0, 0, NULL, filepath);
|
||||||
if (!map) {
|
if (!map) {
|
||||||
cli_dbgmsg("run_pdf_hooks: can't mmap pdf extracted obj\n");
|
cli_dbgmsg("run_pdf_hooks: can't mmap pdf extracted obj\n");
|
||||||
map = ctx->fmap;
|
map = ctx->fmap;
|
||||||
|
@ -1092,7 +1093,7 @@ static int run_pdf_hooks(struct pdf_struct *pdf, enum pdf_phase phase, int fd)
|
||||||
cli_bytecode_context_destroy(bc_ctx);
|
cli_bytecode_context_destroy(bc_ctx);
|
||||||
|
|
||||||
if (fd != -1)
|
if (fd != -1)
|
||||||
funmap(map);
|
fmap_free(map);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -1676,15 +1677,12 @@ cl_error_t pdf_extract_obj(struct pdf_struct *pdf, struct pdf_obj *obj, uint32_t
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
objstm = malloc(sizeof(struct objstm_struct));
|
CLI_CALLOC_OR_GOTO_DONE(
|
||||||
if (!objstm) {
|
objstm, 1, sizeof(struct objstm_struct),
|
||||||
cli_warnmsg("pdf_extract_obj: out of memory parsing object stream (%u)\n", pdf->nobjstms);
|
cli_warnmsg("pdf_extract_obj: out of memory parsing object stream (%u)\n", pdf->nobjstms),
|
||||||
status = CL_EMEM;
|
status = CL_EMEM);
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
pdf->objstms[pdf->nobjstms - 1] = objstm;
|
|
||||||
|
|
||||||
memset(objstm, 0, sizeof(*objstm));
|
pdf->objstms[pdf->nobjstms - 1] = objstm;
|
||||||
|
|
||||||
objstm->first = (size_t)objstm_first;
|
objstm->first = (size_t)objstm_first;
|
||||||
objstm->current = (size_t)objstm_first;
|
objstm->current = (size_t)objstm_first;
|
||||||
|
@ -1802,10 +1800,10 @@ cl_error_t pdf_extract_obj(struct pdf_struct *pdf, struct pdf_obj *obj, uint32_t
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((pdf->ctx->options->general & CL_SCAN_GENERAL_COLLECT_METADATA) && pdf->ctx->wrkproperty != NULL) {
|
if ((pdf->ctx->options->general & CL_SCAN_GENERAL_COLLECT_METADATA) && pdf->ctx->this_layer_metadata_json != NULL) {
|
||||||
struct json_object *pdfobj, *jbig2arr;
|
struct json_object *pdfobj, *jbig2arr;
|
||||||
|
|
||||||
if (NULL == (pdfobj = cli_jsonobj(pdf->ctx->wrkproperty, "PDFStats"))) {
|
if (NULL == (pdfobj = cli_jsonobj(pdf->ctx->this_layer_metadata_json, "PDFStats"))) {
|
||||||
cli_errmsg("pdf_extract_obj: failed to get PDFStats JSON object\n");
|
cli_errmsg("pdf_extract_obj: failed to get PDFStats JSON object\n");
|
||||||
} else if (NULL == (jbig2arr = cli_jsonarray(pdfobj, "JavascriptObjects"))) {
|
} else if (NULL == (jbig2arr = cli_jsonarray(pdfobj, "JavascriptObjects"))) {
|
||||||
cli_errmsg("pdf_extract_obj: failed to get JavascriptObjects JSON object\n");
|
cli_errmsg("pdf_extract_obj: failed to get JavascriptObjects JSON object\n");
|
||||||
|
@ -1886,7 +1884,7 @@ scan_extracted_objects:
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((status == CL_CLEAN) || (status == CL_VIRUS)) {
|
if ((status == CL_CLEAN) || (status == CL_VIRUS)) {
|
||||||
ret = run_pdf_hooks(pdf, PDF_PHASE_POSTDUMP, fout);
|
ret = run_pdf_hooks(pdf, PDF_PHASE_POSTDUMP, fout, fullname);
|
||||||
if (ret == CL_VIRUS) {
|
if (ret == CL_VIRUS) {
|
||||||
status = ret;
|
status = ret;
|
||||||
goto done;
|
goto done;
|
||||||
|
@ -2238,8 +2236,8 @@ void pdf_parseobj(struct pdf_struct *pdf, struct pdf_obj *obj)
|
||||||
if (!nextobj || bytesleft < 0) {
|
if (!nextobj || bytesleft < 0) {
|
||||||
cli_dbgmsg("pdf_parseobj: %u %u obj: no dictionary\n", obj->id >> 8, obj->id & 0xff);
|
cli_dbgmsg("pdf_parseobj: %u %u obj: no dictionary\n", obj->id >> 8, obj->id & 0xff);
|
||||||
|
|
||||||
if (!(pdfobj) && pdf->ctx->wrkproperty != NULL) {
|
if (!(pdfobj) && pdf->ctx->this_layer_metadata_json != NULL) {
|
||||||
pdfobj = cli_jsonobj(pdf->ctx->wrkproperty, "PDFStats");
|
pdfobj = cli_jsonobj(pdf->ctx->this_layer_metadata_json, "PDFStats");
|
||||||
if (!(pdfobj))
|
if (!(pdfobj))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2285,8 +2283,8 @@ void pdf_parseobj(struct pdf_struct *pdf, struct pdf_obj *obj)
|
||||||
if (bytesleft < 0) {
|
if (bytesleft < 0) {
|
||||||
cli_dbgmsg("pdf_parseobj: %u %u obj: broken dictionary\n", obj->id >> 8, obj->id & 0xff);
|
cli_dbgmsg("pdf_parseobj: %u %u obj: broken dictionary\n", obj->id >> 8, obj->id & 0xff);
|
||||||
|
|
||||||
if (!(pdfobj) && pdf->ctx->wrkproperty != NULL) {
|
if (!(pdfobj) && pdf->ctx->this_layer_metadata_json != NULL) {
|
||||||
pdfobj = cli_jsonobj(pdf->ctx->wrkproperty, "PDFStats");
|
pdfobj = cli_jsonobj(pdf->ctx->this_layer_metadata_json, "PDFStats");
|
||||||
if (!(pdfobj))
|
if (!(pdfobj))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2334,8 +2332,8 @@ void pdf_parseobj(struct pdf_struct *pdf, struct pdf_obj *obj)
|
||||||
/* probably truncated */
|
/* probably truncated */
|
||||||
cli_dbgmsg("pdf_parseobj: %u %u obj broken dictionary\n", obj->id >> 8, obj->id & 0xff);
|
cli_dbgmsg("pdf_parseobj: %u %u obj broken dictionary\n", obj->id >> 8, obj->id & 0xff);
|
||||||
|
|
||||||
if (!(pdfobj) && pdf->ctx->wrkproperty != NULL) {
|
if (!(pdfobj) && pdf->ctx->this_layer_metadata_json != NULL) {
|
||||||
pdfobj = cli_jsonobj(pdf->ctx->wrkproperty, "PDFStats");
|
pdfobj = cli_jsonobj(pdf->ctx->this_layer_metadata_json, "PDFStats");
|
||||||
if (!(pdfobj))
|
if (!(pdfobj))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -2883,7 +2881,7 @@ static void compute_hash_r6(const char *password, size_t pwlen, const unsigned c
|
||||||
int32_t block_size = 32;
|
int32_t block_size = 32;
|
||||||
size_t in_data_len = 0, out_data_len;
|
size_t in_data_len = 0, out_data_len;
|
||||||
int32_t i, j, sum;
|
int32_t i, j, sum;
|
||||||
uint8_t sha256[32], sha384[48], sha512[64];
|
uint8_t sha2_256[32], sha2_384[48], sha2_512[64];
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Compute a SHA-256 hash of the UTF-8 password concatenated with the 8 bytes of the owner or user validation salt.
|
* Compute a SHA-256 hash of the UTF-8 password concatenated with the 8 bytes of the owner or user validation salt.
|
||||||
|
@ -2923,18 +2921,18 @@ static void compute_hash_r6(const char *password, size_t pwlen, const unsigned c
|
||||||
block_size = 32 + (sum % 3) * 16;
|
block_size = 32 + (sum % 3) * 16;
|
||||||
switch (block_size) {
|
switch (block_size) {
|
||||||
case 32:
|
case 32:
|
||||||
cl_sha256(data, in_data_len * 64, sha256, NULL);
|
cl_sha256(data, in_data_len * 64, sha2_256, NULL);
|
||||||
memcpy(block, sha256, 32);
|
memcpy(block, sha2_256, 32);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 48:
|
case 48:
|
||||||
cl_sha384(data, in_data_len * 64, sha384, NULL);
|
cl_sha384(data, in_data_len * 64, sha2_384, NULL);
|
||||||
memcpy(block, sha384, 48);
|
memcpy(block, sha2_384, 48);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 64:
|
case 64:
|
||||||
cl_sha512(data, in_data_len * 64, sha512, NULL);
|
cl_sha512(data, in_data_len * 64, sha2_512, NULL);
|
||||||
memcpy(block, sha512, 64);
|
memcpy(block, sha2_512, 64);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3692,7 +3690,7 @@ static cl_error_t pdf_find_and_extract_objs(struct pdf_struct *pdf)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CL_SUCCESS == status) {
|
if (CL_SUCCESS == status) {
|
||||||
status = run_pdf_hooks(pdf, PDF_PHASE_PARSED, -1);
|
status = run_pdf_hooks(pdf, PDF_PHASE_PARSED, -1, NULL);
|
||||||
cli_dbgmsg("pdf_find_and_extract_objs: (parsed hooks) returned %d\n", status);
|
cli_dbgmsg("pdf_find_and_extract_objs: (parsed hooks) returned %d\n", status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3776,8 +3774,8 @@ cl_error_t cli_pdf(const char *dir, cli_ctx *ctx, off_t offset)
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx->wrkproperty)
|
if (ctx->this_layer_metadata_json)
|
||||||
pdfobj = cli_jsonobj(ctx->wrkproperty, "PDFStats");
|
pdfobj = cli_jsonobj(ctx->this_layer_metadata_json, "PDFStats");
|
||||||
|
|
||||||
/* offset is 0 when coming from filetype2 */
|
/* offset is 0 when coming from filetype2 */
|
||||||
tmp = cli_memstr(pdfver, versize, "%PDF-", 5);
|
tmp = cli_memstr(pdfver, versize, "%PDF-", 5);
|
||||||
|
@ -3919,7 +3917,7 @@ cl_error_t cli_pdf(const char *dir, cli_ctx *ctx, off_t offset)
|
||||||
|
|
||||||
pdf.startoff = offset;
|
pdf.startoff = offset;
|
||||||
|
|
||||||
rc = run_pdf_hooks(&pdf, PDF_PHASE_PRE, -1);
|
rc = run_pdf_hooks(&pdf, PDF_PHASE_PRE, -1, NULL);
|
||||||
if (CL_SUCCESS != rc) {
|
if (CL_SUCCESS != rc) {
|
||||||
cli_dbgmsg("cli_pdf: (pre hooks) returning %d\n", rc);
|
cli_dbgmsg("cli_pdf: (pre hooks) returning %d\n", rc);
|
||||||
|
|
||||||
|
@ -3948,7 +3946,7 @@ cl_error_t cli_pdf(const char *dir, cli_ctx *ctx, off_t offset)
|
||||||
|
|
||||||
if (pdf.flags && CL_SUCCESS == rc) {
|
if (pdf.flags && CL_SUCCESS == rc) {
|
||||||
cli_dbgmsg("cli_pdf: flags 0x%02x\n", pdf.flags);
|
cli_dbgmsg("cli_pdf: flags 0x%02x\n", pdf.flags);
|
||||||
rc = run_pdf_hooks(&pdf, PDF_PHASE_END, -1);
|
rc = run_pdf_hooks(&pdf, PDF_PHASE_END, -1, NULL);
|
||||||
|
|
||||||
if (CL_SUCCESS == rc && SCAN_HEURISTICS && (ctx->dconf->other & OTHER_CONF_PDFNAMEOBJ)) {
|
if (CL_SUCCESS == rc && SCAN_HEURISTICS && (ctx->dconf->other & OTHER_CONF_PDFNAMEOBJ)) {
|
||||||
if (pdf.flags & (1 << ESCAPED_COMMON_PDFNAME)) {
|
if (pdf.flags & (1 << ESCAPED_COMMON_PDFNAME)) {
|
||||||
|
@ -4222,10 +4220,10 @@ static void JBIG2Decode_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct p
|
||||||
if (!(SCAN_COLLECT_METADATA))
|
if (!(SCAN_COLLECT_METADATA))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!(pdf->ctx->wrkproperty))
|
if (!(pdf->ctx->this_layer_metadata_json))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
pdfobj = cli_jsonobj(pdf->ctx->wrkproperty, "PDFStats");
|
pdfobj = cli_jsonobj(pdf->ctx->this_layer_metadata_json, "PDFStats");
|
||||||
if (!(pdfobj))
|
if (!(pdfobj))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -4612,7 +4610,7 @@ static void Pages_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname
|
||||||
|
|
||||||
UNUSEDPARAM(act);
|
UNUSEDPARAM(act);
|
||||||
|
|
||||||
if (!(pdf) || !(pdf->ctx->wrkproperty))
|
if (!(pdf) || !(pdf->ctx->this_layer_metadata_json))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ctx = pdf->ctx;
|
ctx = pdf->ctx;
|
||||||
|
@ -4620,7 +4618,7 @@ static void Pages_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname
|
||||||
if (!(SCAN_COLLECT_METADATA))
|
if (!(SCAN_COLLECT_METADATA))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
pdfobj = cli_jsonobj(pdf->ctx->wrkproperty, "PDFStats");
|
pdfobj = cli_jsonobj(pdf->ctx->this_layer_metadata_json, "PDFStats");
|
||||||
if (!(pdfobj))
|
if (!(pdfobj))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -4688,7 +4686,7 @@ static void Colors_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfnam
|
||||||
|
|
||||||
UNUSEDPARAM(act);
|
UNUSEDPARAM(act);
|
||||||
|
|
||||||
if (!(pdf) || !(pdf->ctx) || !(pdf->ctx->wrkproperty))
|
if (!(pdf) || !(pdf->ctx) || !(pdf->ctx->this_layer_metadata_json))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ctx = pdf->ctx;
|
ctx = pdf->ctx;
|
||||||
|
@ -4723,7 +4721,7 @@ static void Colors_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfnam
|
||||||
if (ncolors < 1 << 24)
|
if (ncolors < 1 << 24)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
pdfobj = cli_jsonobj(pdf->ctx->wrkproperty, "PDFStats");
|
pdfobj = cli_jsonobj(pdf->ctx->this_layer_metadata_json, "PDFStats");
|
||||||
if (!(pdfobj))
|
if (!(pdfobj))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -4745,7 +4743,7 @@ static void URI_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname_a
|
||||||
|
|
||||||
UNUSEDPARAM(act);
|
UNUSEDPARAM(act);
|
||||||
|
|
||||||
if (!(pdf) || !(pdf->ctx) || !(pdf->ctx->wrkproperty) || !obj) {
|
if (!(pdf) || !(pdf->ctx) || !(pdf->ctx->this_layer_metadata_json) || !obj) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4796,7 +4794,7 @@ static void URI_cb(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdfname_a
|
||||||
strncpy(uri_heap, uri_start, end);
|
strncpy(uri_heap, uri_start, end);
|
||||||
uri_heap[end] = '\0';
|
uri_heap[end] = '\0';
|
||||||
|
|
||||||
uriarr = cli_jsonarray(pdf->ctx->wrkproperty, "URIs");
|
uriarr = cli_jsonarray(pdf->ctx->this_layer_metadata_json, "URIs");
|
||||||
if (!uriarr) {
|
if (!uriarr) {
|
||||||
cli_errmsg("cli_pdf: malloc() failed (URI array)\n");
|
cli_errmsg("cli_pdf: malloc() failed (URI array)\n");
|
||||||
goto done;
|
goto done;
|
||||||
|
@ -4885,11 +4883,11 @@ static void pdf_export_json(struct pdf_struct *pdf)
|
||||||
|
|
||||||
ctx = pdf->ctx;
|
ctx = pdf->ctx;
|
||||||
|
|
||||||
if (!(SCAN_COLLECT_METADATA) || !(pdf->ctx->wrkproperty)) {
|
if (!(SCAN_COLLECT_METADATA) || !(pdf->ctx->this_layer_metadata_json)) {
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
pdfobj = cli_jsonobj(pdf->ctx->wrkproperty, "PDFStats");
|
pdfobj = cli_jsonobj(pdf->ctx->this_layer_metadata_json, "PDFStats");
|
||||||
if (!(pdfobj)) {
|
if (!(pdfobj)) {
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
|
@ -135,11 +135,9 @@ size_t pdf_decodestream(
|
||||||
pdf_print_dict(params, 0);
|
pdf_print_dict(params, 0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
token = malloc(sizeof(struct pdf_token));
|
CLI_CALLOC_OR_GOTO_DONE(
|
||||||
if (!token) {
|
token, 1, sizeof(struct pdf_token),
|
||||||
*status = CL_EMEM;
|
*status = CL_EMEM);
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
token->flags = 0;
|
token->flags = 0;
|
||||||
if (xref)
|
if (xref)
|
||||||
|
@ -147,11 +145,9 @@ size_t pdf_decodestream(
|
||||||
|
|
||||||
token->success = 0;
|
token->success = 0;
|
||||||
|
|
||||||
token->content = cli_max_malloc(streamlen);
|
CLI_MAX_CALLOC_OR_GOTO_DONE(
|
||||||
if (!token->content) {
|
token->content, 1, streamlen,
|
||||||
*status = CL_EMEM;
|
*status = CL_EMEM);
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(token->content, stream, streamlen);
|
memcpy(token->content, stream, streamlen);
|
||||||
token->length = streamlen;
|
token->length = streamlen;
|
||||||
|
@ -890,7 +886,8 @@ static cl_error_t filter_decrypt(struct pdf_struct *pdf, struct pdf_obj *obj, st
|
||||||
|
|
||||||
static cl_error_t filter_lzwdecode(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdf_dict *params, struct pdf_token *token)
|
static cl_error_t filter_lzwdecode(struct pdf_struct *pdf, struct pdf_obj *obj, struct pdf_dict *params, struct pdf_token *token)
|
||||||
{
|
{
|
||||||
uint8_t *decoded, *temp;
|
uint8_t *decoded = NULL;
|
||||||
|
uint8_t *temp = NULL;
|
||||||
size_t declen = 0, capacity = 0;
|
size_t declen = 0, capacity = 0;
|
||||||
|
|
||||||
uint8_t *content = (uint8_t *)token->content;
|
uint8_t *content = (uint8_t *)token->content;
|
||||||
|
@ -1093,7 +1090,7 @@ done:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rc == CL_SUCCESS || rc == CL_BREAK) {
|
if ((rc == CL_SUCCESS || rc == CL_BREAK) && (NULL != decoded)) {
|
||||||
free(token->content);
|
free(token->content);
|
||||||
|
|
||||||
token->content = decoded;
|
token->content = decoded;
|
||||||
|
|
206
libclamav/pe.c
206
libclamav/pe.c
|
@ -125,7 +125,7 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
#define CLI_UNPTEMP(NAME, FREEME) \
|
#define CLI_UNPTEMP(NAME, FREEME) \
|
||||||
if (!(tempfile = cli_gentemp(ctx->sub_tmpdir))) { \
|
if (!(tempfile = cli_gentemp(ctx->this_layer_tmpdir))) { \
|
||||||
cli_exe_info_destroy(peinfo); \
|
cli_exe_info_destroy(peinfo); \
|
||||||
cli_multifree FREEME; \
|
cli_multifree FREEME; \
|
||||||
return CL_EMEM; \
|
return CL_EMEM; \
|
||||||
|
@ -146,24 +146,6 @@
|
||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef HAVE__INTERNAL__SHA_COLLECT
|
|
||||||
#define SHA_OFF \
|
|
||||||
do { \
|
|
||||||
ctx->sha_collect = -1; \
|
|
||||||
} while (0)
|
|
||||||
#define SHA_RESET \
|
|
||||||
do { \
|
|
||||||
ctx->sha_collect = sha_collect; \
|
|
||||||
} while (0)
|
|
||||||
#else
|
|
||||||
#define SHA_OFF \
|
|
||||||
do { \
|
|
||||||
} while (0)
|
|
||||||
#define SHA_RESET \
|
|
||||||
do { \
|
|
||||||
} while (0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#define FSGCASE(NAME, FREESEC) \
|
#define FSGCASE(NAME, FREESEC) \
|
||||||
case 0: /* Unpacked and NOT rebuilt */ \
|
case 0: /* Unpacked and NOT rebuilt */ \
|
||||||
cli_dbgmsg(NAME ": Successfully decompressed\n"); \
|
cli_dbgmsg(NAME ": Successfully decompressed\n"); \
|
||||||
|
@ -201,15 +183,12 @@
|
||||||
cli_exe_info_destroy(peinfo); \
|
cli_exe_info_destroy(peinfo); \
|
||||||
lseek(ndesc, 0, SEEK_SET); \
|
lseek(ndesc, 0, SEEK_SET); \
|
||||||
cli_dbgmsg("***** Scanning rebuilt PE file *****\n"); \
|
cli_dbgmsg("***** Scanning rebuilt PE file *****\n"); \
|
||||||
SHA_OFF; \
|
|
||||||
if (CL_SUCCESS != (ret = cli_magic_scan_desc(ndesc, tempfile, ctx, NULL, LAYER_ATTRIBUTES_NONE))) { \
|
if (CL_SUCCESS != (ret = cli_magic_scan_desc(ndesc, tempfile, ctx, NULL, LAYER_ATTRIBUTES_NONE))) { \
|
||||||
close(ndesc); \
|
close(ndesc); \
|
||||||
SHA_RESET; \
|
|
||||||
CLI_TMPUNLK(); \
|
CLI_TMPUNLK(); \
|
||||||
free(tempfile); \
|
free(tempfile); \
|
||||||
return ret; \
|
return ret; \
|
||||||
} \
|
} \
|
||||||
SHA_RESET; \
|
|
||||||
close(ndesc); \
|
close(ndesc); \
|
||||||
CLI_TMPUNLK(); \
|
CLI_TMPUNLK(); \
|
||||||
free(tempfile); \
|
free(tempfile); \
|
||||||
|
@ -241,8 +220,6 @@
|
||||||
|
|
||||||
#define DETECT_BROKEN_PE (SCAN_HEURISTIC_BROKEN && !ctx->corrupted_input)
|
#define DETECT_BROKEN_PE (SCAN_HEURISTIC_BROKEN && !ctx->corrupted_input)
|
||||||
|
|
||||||
extern const unsigned int hashlen[];
|
|
||||||
|
|
||||||
struct offset_list {
|
struct offset_list {
|
||||||
uint32_t offset;
|
uint32_t offset;
|
||||||
struct offset_list *next;
|
struct offset_list *next;
|
||||||
|
@ -530,49 +507,49 @@ static void cli_parseres_special(uint32_t base, uint32_t rva, fmap_t *map, struc
|
||||||
fmap_unneed_ptr(map, oentry, entries * 8);
|
fmap_unneed_ptr(map, oentry, entries * 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int cli_hashsect(fmap_t *map, struct cli_exe_section *s, unsigned char **digest, int *foundhash, int *foundwild)
|
static bool cli_hashsect(fmap_t *map, struct cli_exe_section *s, uint8_t **digest, bool *foundhash, bool *foundwild)
|
||||||
{
|
{
|
||||||
const void *hashme;
|
const void *hashme;
|
||||||
|
|
||||||
if (s->rsz > CLI_MAX_ALLOCATION) {
|
if (s->rsz > CLI_MAX_ALLOCATION) {
|
||||||
cli_dbgmsg("cli_hashsect: skipping hash calculation for too big section\n");
|
cli_dbgmsg("cli_hashsect: skipping hash calculation for too big section\n");
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!s->rsz) return 0;
|
if (!s->rsz) return false;
|
||||||
if (!(hashme = fmap_need_off_once(map, s->raw, s->rsz))) {
|
if (!(hashme = fmap_need_off_once(map, s->raw, s->rsz))) {
|
||||||
cli_dbgmsg("cli_hashsect: unable to read section data\n");
|
cli_dbgmsg("cli_hashsect: unable to read section data\n");
|
||||||
return 0;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (foundhash[CLI_HASH_MD5] || foundwild[CLI_HASH_MD5])
|
if (foundhash[CLI_HASH_MD5] || foundwild[CLI_HASH_MD5])
|
||||||
cl_hash_data("md5", hashme, s->rsz, digest[CLI_HASH_MD5], NULL);
|
cl_hash_data("md5", hashme, s->rsz, digest[CLI_HASH_MD5], NULL);
|
||||||
if (foundhash[CLI_HASH_SHA1] || foundwild[CLI_HASH_SHA1])
|
if (foundhash[CLI_HASH_SHA1] || foundwild[CLI_HASH_SHA1])
|
||||||
cl_sha1(hashme, s->rsz, digest[CLI_HASH_SHA1], NULL);
|
cl_sha1(hashme, s->rsz, digest[CLI_HASH_SHA1], NULL);
|
||||||
if (foundhash[CLI_HASH_SHA256] || foundwild[CLI_HASH_SHA256])
|
if (foundhash[CLI_HASH_SHA2_256] || foundwild[CLI_HASH_SHA2_256])
|
||||||
cl_sha256(hashme, s->rsz, digest[CLI_HASH_SHA256], NULL);
|
cl_sha256(hashme, s->rsz, digest[CLI_HASH_SHA2_256], NULL);
|
||||||
|
|
||||||
return 1;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check hash section sigs */
|
/* check hash section sigs */
|
||||||
static cl_error_t scan_pe_mdb(cli_ctx *ctx, struct cli_exe_section *exe_section)
|
static cl_error_t scan_pe_mdb(cli_ctx *ctx, struct cli_exe_section *exe_section)
|
||||||
{
|
{
|
||||||
struct cli_matcher *mdb_sect = ctx->engine->hm_mdb;
|
struct cli_matcher *mdb_sect = ctx->engine->hm_mdb;
|
||||||
unsigned char *hashset[CLI_HASH_AVAIL_TYPES];
|
uint8_t *hashset[CLI_HASH_AVAIL_TYPES];
|
||||||
const char *virname = NULL;
|
const char *virname = NULL;
|
||||||
int foundsize[CLI_HASH_AVAIL_TYPES];
|
bool foundsize[CLI_HASH_AVAIL_TYPES];
|
||||||
int foundwild[CLI_HASH_AVAIL_TYPES];
|
bool foundwild[CLI_HASH_AVAIL_TYPES];
|
||||||
cli_hash_type_t type;
|
cli_hash_type_t type;
|
||||||
cl_error_t ret = CL_CLEAN;
|
cl_error_t ret = CL_CLEAN;
|
||||||
unsigned char *md5 = NULL;
|
uint8_t *md5 = NULL;
|
||||||
|
|
||||||
/* pick hashtypes to generate */
|
/* pick hashtypes to generate */
|
||||||
for (type = CLI_HASH_MD5; type < CLI_HASH_AVAIL_TYPES; type++) {
|
for (type = CLI_HASH_MD5; type < CLI_HASH_AVAIL_TYPES; type++) {
|
||||||
foundsize[type] = cli_hm_have_size(mdb_sect, type, exe_section->rsz);
|
foundsize[type] = cli_hm_have_size(mdb_sect, type, exe_section->rsz);
|
||||||
foundwild[type] = cli_hm_have_wild(mdb_sect, type);
|
foundwild[type] = cli_hm_have_wild(mdb_sect, type);
|
||||||
if (foundsize[type] || foundwild[type]) {
|
if (foundsize[type] || foundwild[type]) {
|
||||||
hashset[type] = malloc(hashlen[type]);
|
hashset[type] = malloc(cli_hash_len(type));
|
||||||
if (!hashset[type]) {
|
if (!hashset[type]) {
|
||||||
cli_errmsg("scan_pe_mdb: malloc failed!\n");
|
cli_errmsg("scan_pe_mdb: malloc failed!\n");
|
||||||
for (; type > 0;)
|
for (; type > 0;)
|
||||||
|
@ -639,7 +616,7 @@ static cl_error_t scan_pe_mdb(cli_ctx *ctx, struct cli_exe_section *exe_section)
|
||||||
}
|
}
|
||||||
|
|
||||||
end:
|
end:
|
||||||
for (type = CLI_HASH_AVAIL_TYPES; type > 0;)
|
for (type = CLI_HASH_AVAIL_TYPES; type > CLI_HASH_MD5;)
|
||||||
free(hashset[--type]);
|
free(hashset[--type]);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -2258,8 +2235,8 @@ static inline int hash_impfns(cli_ctx *ctx, void **hashctx, uint32_t *impsz, str
|
||||||
return CL_EFORMAT;
|
return CL_EFORMAT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctx->wrkproperty) {
|
if (ctx->this_layer_metadata_json) {
|
||||||
imptbl = cli_jsonarray(ctx->wrkproperty, "ImportTable");
|
imptbl = cli_jsonarray(ctx->this_layer_metadata_json, "ImportTable");
|
||||||
if (!imptbl) {
|
if (!imptbl) {
|
||||||
cli_dbgmsg("scan_pe: cannot allocate import table json object\n");
|
cli_dbgmsg("scan_pe: cannot allocate import table json object\n");
|
||||||
return CL_EMEM;
|
return CL_EMEM;
|
||||||
|
@ -2405,7 +2382,7 @@ static inline int hash_impfns(cli_ctx *ctx, void **hashctx, uint32_t *impsz, str
|
||||||
return CL_SUCCESS;
|
return CL_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static cl_error_t hash_imptbl(cli_ctx *ctx, unsigned char **digest, uint32_t *impsz, int *genhash, struct cli_exe_info *peinfo)
|
static cl_error_t hash_imptbl(cli_ctx *ctx, uint8_t **digest, uint32_t *impsz, bool *genhash, struct cli_exe_info *peinfo)
|
||||||
{
|
{
|
||||||
cl_error_t status = CL_ERROR;
|
cl_error_t status = CL_ERROR;
|
||||||
cl_error_t ret;
|
cl_error_t ret;
|
||||||
|
@ -2415,7 +2392,7 @@ static cl_error_t hash_imptbl(cli_ctx *ctx, unsigned char **digest, uint32_t *im
|
||||||
size_t left, fsize = map->len;
|
size_t left, fsize = map->len;
|
||||||
uint32_t impoff, offset;
|
uint32_t impoff, offset;
|
||||||
const char *buffer;
|
const char *buffer;
|
||||||
void *hashctx[CLI_HASH_AVAIL_TYPES] = {0};
|
void *hashctx[CLI_HASH_AVAIL_TYPES] = {NULL};
|
||||||
cli_hash_type_t type;
|
cli_hash_type_t type;
|
||||||
int nimps = 0;
|
int nimps = 0;
|
||||||
unsigned int err;
|
unsigned int err;
|
||||||
|
@ -2451,25 +2428,14 @@ static cl_error_t hash_imptbl(cli_ctx *ctx, unsigned char **digest, uint32_t *im
|
||||||
* would have failed if the size exceeds the end of the fmap. */
|
* would have failed if the size exceeds the end of the fmap. */
|
||||||
left = peinfo->dirs[1].Size;
|
left = peinfo->dirs[1].Size;
|
||||||
|
|
||||||
if (genhash[CLI_HASH_MD5]) {
|
for (type = CLI_HASH_MD5; type < CLI_HASH_AVAIL_TYPES; type++) {
|
||||||
hashctx[CLI_HASH_MD5] = cl_hash_init("md5");
|
if (genhash[type]) {
|
||||||
if (hashctx[CLI_HASH_MD5] == NULL) {
|
hashctx[type] = cl_hash_init(cli_hash_name(type));
|
||||||
status = CL_EMEM;
|
if (hashctx[type] == NULL) {
|
||||||
goto done;
|
cli_dbgmsg("scan_pe: cannot initialize hash context for %s\n", cli_hash_name(type));
|
||||||
}
|
status = CL_EMEM;
|
||||||
}
|
goto done;
|
||||||
if (genhash[CLI_HASH_SHA1]) {
|
}
|
||||||
hashctx[CLI_HASH_SHA1] = cl_hash_init("sha1");
|
|
||||||
if (hashctx[CLI_HASH_SHA1] == NULL) {
|
|
||||||
status = CL_EMEM;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (genhash[CLI_HASH_SHA256]) {
|
|
||||||
hashctx[CLI_HASH_SHA256] = cl_hash_init("sha256");
|
|
||||||
if (hashctx[CLI_HASH_SHA256] == NULL) {
|
|
||||||
status = CL_EMEM;
|
|
||||||
goto done;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2570,11 +2536,11 @@ done:
|
||||||
|
|
||||||
static cl_error_t scan_pe_imp(cli_ctx *ctx, struct cli_exe_info *peinfo)
|
static cl_error_t scan_pe_imp(cli_ctx *ctx, struct cli_exe_info *peinfo)
|
||||||
{
|
{
|
||||||
struct cli_matcher *imp = ctx->engine->hm_imp;
|
struct cli_matcher *imp = ctx->engine->hm_imp;
|
||||||
unsigned char *hashset[CLI_HASH_AVAIL_TYPES];
|
uint8_t *hashset[CLI_HASH_AVAIL_TYPES] = {NULL};
|
||||||
const char *virname = NULL;
|
bool genhash[CLI_HASH_AVAIL_TYPES] = {false};
|
||||||
int genhash[CLI_HASH_AVAIL_TYPES];
|
const char *virname = NULL;
|
||||||
uint32_t impsz = 0;
|
uint32_t impsz = 0;
|
||||||
cli_hash_type_t type;
|
cli_hash_type_t type;
|
||||||
cl_error_t ret = CL_CLEAN;
|
cl_error_t ret = CL_CLEAN;
|
||||||
|
|
||||||
|
@ -2582,7 +2548,7 @@ static cl_error_t scan_pe_imp(cli_ctx *ctx, struct cli_exe_info *peinfo)
|
||||||
for (type = CLI_HASH_MD5; type < CLI_HASH_AVAIL_TYPES; type++) {
|
for (type = CLI_HASH_MD5; type < CLI_HASH_AVAIL_TYPES; type++) {
|
||||||
genhash[type] = cli_hm_have_any(imp, type);
|
genhash[type] = cli_hm_have_any(imp, type);
|
||||||
if (genhash[type]) {
|
if (genhash[type]) {
|
||||||
hashset[type] = malloc(hashlen[type]);
|
hashset[type] = malloc(cli_hash_len(type));
|
||||||
if (!hashset[type]) {
|
if (!hashset[type]) {
|
||||||
cli_errmsg("scan_pe: malloc failed!\n");
|
cli_errmsg("scan_pe: malloc failed!\n");
|
||||||
for (; type > 0;)
|
for (; type > 0;)
|
||||||
|
@ -2595,9 +2561,9 @@ static cl_error_t scan_pe_imp(cli_ctx *ctx, struct cli_exe_info *peinfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Force md5 hash generation for debug and preclass */
|
/* Force md5 hash generation for debug and preclass */
|
||||||
if ((cli_debug_flag || ctx->wrkproperty) && !genhash[CLI_HASH_MD5]) {
|
if ((cli_debug_flag || ctx->this_layer_metadata_json) && !genhash[CLI_HASH_MD5]) {
|
||||||
genhash[CLI_HASH_MD5] = 1;
|
genhash[CLI_HASH_MD5] = true;
|
||||||
hashset[CLI_HASH_MD5] = calloc(hashlen[CLI_HASH_MD5], sizeof(char));
|
hashset[CLI_HASH_MD5] = calloc(cli_hash_len(CLI_HASH_MD5), sizeof(char));
|
||||||
if (!hashset[CLI_HASH_MD5]) {
|
if (!hashset[CLI_HASH_MD5]) {
|
||||||
cli_errmsg("scan_pe: calloc failed!\n");
|
cli_errmsg("scan_pe: calloc failed!\n");
|
||||||
for (type = CLI_HASH_MD5; type < CLI_HASH_AVAIL_TYPES; type++)
|
for (type = CLI_HASH_MD5; type < CLI_HASH_AVAIL_TYPES; type++)
|
||||||
|
@ -2619,12 +2585,12 @@ static cl_error_t scan_pe_imp(cli_ctx *ctx, struct cli_exe_info *peinfo)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Print hash */
|
/* Print hash */
|
||||||
if (cli_debug_flag || ctx->wrkproperty) {
|
if (cli_debug_flag || ctx->this_layer_metadata_json) {
|
||||||
char *dstr = cli_str2hex((char *)hashset[CLI_HASH_MD5], hashlen[CLI_HASH_MD5]);
|
char *dstr = cli_str2hex((char *)hashset[CLI_HASH_MD5], cli_hash_len(CLI_HASH_MD5));
|
||||||
cli_dbgmsg("IMP: %s:%u\n", dstr ? (char *)dstr : "(NULL)", impsz);
|
cli_dbgmsg("IMP: %s:%u\n", dstr ? (char *)dstr : "(NULL)", impsz);
|
||||||
|
|
||||||
if (ctx->wrkproperty)
|
if (ctx->this_layer_metadata_json)
|
||||||
cli_jsonstr(ctx->wrkproperty, "Imphash", dstr ? dstr : "(NULL)");
|
cli_jsonstr(ctx->this_layer_metadata_json, "Imphash", dstr ? dstr : "(NULL)");
|
||||||
|
|
||||||
if (dstr)
|
if (dstr)
|
||||||
free(dstr);
|
free(dstr);
|
||||||
|
@ -2655,15 +2621,15 @@ static struct json_object *get_pe_property(cli_ctx *ctx)
|
||||||
{
|
{
|
||||||
struct json_object *pe;
|
struct json_object *pe;
|
||||||
|
|
||||||
if (!(ctx) || !(ctx->wrkproperty))
|
if (!(ctx) || !(ctx->this_layer_metadata_json))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
if (!json_object_object_get_ex(ctx->wrkproperty, "PE", &pe)) {
|
if (!json_object_object_get_ex(ctx->this_layer_metadata_json, "PE", &pe)) {
|
||||||
pe = json_object_new_object();
|
pe = json_object_new_object();
|
||||||
if (!(pe))
|
if (!(pe))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
json_object_object_add(ctx->wrkproperty, "PE", pe);
|
json_object_object_add(ctx->this_layer_metadata_json, "PE", pe);
|
||||||
}
|
}
|
||||||
|
|
||||||
return pe;
|
return pe;
|
||||||
|
@ -2781,9 +2747,6 @@ int cli_scanpe(cli_ctx *ctx)
|
||||||
struct cli_bc_ctx *bc_ctx;
|
struct cli_bc_ctx *bc_ctx;
|
||||||
fmap_t *map;
|
fmap_t *map;
|
||||||
struct cli_pe_hook_data pedata;
|
struct cli_pe_hook_data pedata;
|
||||||
#ifdef HAVE__INTERNAL__SHA_COLLECT
|
|
||||||
int sha_collect = ctx->sha_collect;
|
|
||||||
#endif
|
|
||||||
int toval = 0;
|
int toval = 0;
|
||||||
struct json_object *pe_json = NULL;
|
struct json_object *pe_json = NULL;
|
||||||
|
|
||||||
|
@ -2900,7 +2863,7 @@ int cli_scanpe(cli_ctx *ctx)
|
||||||
|
|
||||||
/* CLI_UNPTEMP("cli_scanpe: DISASM",(peinfo->sections,0)); */
|
/* CLI_UNPTEMP("cli_scanpe: DISASM",(peinfo->sections,0)); */
|
||||||
/* if(disasmbuf((unsigned char*)epbuff, epsize, ndesc)) */
|
/* if(disasmbuf((unsigned char*)epbuff, epsize, ndesc)) */
|
||||||
/* ret = cli_scan_desc(ndesc, ctx, CL_TYPE_PE_DISASM, true, NULL, AC_SCAN_VIR); */
|
/* ret = cli_scan_desc(ndesc, ctx, CL_TYPE_PE_DISASM, true, NULL, NULL, AC_SCAN_VIR); */
|
||||||
/* close(ndesc); */
|
/* close(ndesc); */
|
||||||
/* if(ret == CL_VIRUS) { */
|
/* if(ret == CL_VIRUS) { */
|
||||||
/* cli_exe_info_destroy(peinfo); */
|
/* cli_exe_info_destroy(peinfo); */
|
||||||
|
@ -2962,7 +2925,7 @@ int cli_scanpe(cli_ctx *ctx)
|
||||||
|
|
||||||
/* Attempt to run scans on import table */
|
/* Attempt to run scans on import table */
|
||||||
/* Run if there are existing signatures and/or preclassing */
|
/* Run if there are existing signatures and/or preclassing */
|
||||||
if (DCONF & PE_CONF_IMPTBL && (ctx->engine->hm_imp || ctx->wrkproperty)) {
|
if (DCONF & PE_CONF_IMPTBL && (ctx->engine->hm_imp || ctx->this_layer_metadata_json)) {
|
||||||
ret = scan_pe_imp(ctx, peinfo);
|
ret = scan_pe_imp(ctx, peinfo);
|
||||||
switch (ret) {
|
switch (ret) {
|
||||||
case CL_SUCCESS:
|
case CL_SUCCESS:
|
||||||
|
@ -3932,7 +3895,6 @@ int cli_scanpe(cli_ctx *ctx)
|
||||||
if (lseek(ndesc, 0, SEEK_SET) == -1) {
|
if (lseek(ndesc, 0, SEEK_SET) == -1) {
|
||||||
cli_dbgmsg("cli_scanpe: UPX/FSG: lseek() failed\n");
|
cli_dbgmsg("cli_scanpe: UPX/FSG: lseek() failed\n");
|
||||||
close(ndesc);
|
close(ndesc);
|
||||||
SHA_RESET;
|
|
||||||
CLI_TMPUNLK();
|
CLI_TMPUNLK();
|
||||||
free(tempfile);
|
free(tempfile);
|
||||||
return CL_ESEEK;
|
return CL_ESEEK;
|
||||||
|
@ -3942,17 +3904,14 @@ int cli_scanpe(cli_ctx *ctx)
|
||||||
cli_dbgmsg("cli_scanpe: UPX/FSG: Decompressed data saved in %s\n", tempfile);
|
cli_dbgmsg("cli_scanpe: UPX/FSG: Decompressed data saved in %s\n", tempfile);
|
||||||
|
|
||||||
cli_dbgmsg("***** Scanning decompressed file *****\n");
|
cli_dbgmsg("***** Scanning decompressed file *****\n");
|
||||||
SHA_OFF;
|
|
||||||
ret = cli_magic_scan_desc(ndesc, tempfile, ctx, NULL, LAYER_ATTRIBUTES_NONE);
|
ret = cli_magic_scan_desc(ndesc, tempfile, ctx, NULL, LAYER_ATTRIBUTES_NONE);
|
||||||
if (CL_SUCCESS != ret) {
|
if (CL_SUCCESS != ret) {
|
||||||
close(ndesc);
|
close(ndesc);
|
||||||
SHA_RESET;
|
|
||||||
CLI_TMPUNLK();
|
CLI_TMPUNLK();
|
||||||
free(tempfile);
|
free(tempfile);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
SHA_RESET;
|
|
||||||
close(ndesc);
|
close(ndesc);
|
||||||
CLI_TMPUNLK();
|
CLI_TMPUNLK();
|
||||||
free(tempfile);
|
free(tempfile);
|
||||||
|
@ -4119,7 +4078,7 @@ int cli_scanpe(cli_ctx *ctx)
|
||||||
cli_jsonstr(pe_json, "Packer", "yC");
|
cli_jsonstr(pe_json, "Packer", "yC");
|
||||||
|
|
||||||
// record number of alerts before unpacking and scanning
|
// record number of alerts before unpacking and scanning
|
||||||
num_alerts = evidence_num_alerts(ctx->evidence);
|
num_alerts = evidence_num_alerts(ctx->this_layer_evidence);
|
||||||
|
|
||||||
cli_dbgmsg("%d,%d,%d,%d\n", peinfo->nsections - 1, peinfo->e_lfanew, ecx, offset);
|
cli_dbgmsg("%d,%d,%d,%d\n", peinfo->nsections - 1, peinfo->e_lfanew, ecx, offset);
|
||||||
CLI_UNPTEMP("cli_scanpe: yC", (spinned, 0));
|
CLI_UNPTEMP("cli_scanpe: yC", (spinned, 0));
|
||||||
|
@ -4131,7 +4090,7 @@ int cli_scanpe(cli_ctx *ctx)
|
||||||
//
|
//
|
||||||
// This preserves the intention of https://github.com/Cisco-Talos/clamav/commit/771c23099893f02f1316960fbe84f62b115a3556
|
// This preserves the intention of https://github.com/Cisco-Talos/clamav/commit/771c23099893f02f1316960fbe84f62b115a3556
|
||||||
// although that commit had it bailing if a match occurred even in allmatch-mode, which we do not want to do.
|
// although that commit had it bailing if a match occurred even in allmatch-mode, which we do not want to do.
|
||||||
if (!SCAN_ALLMATCHES && num_alerts != evidence_num_alerts(ctx->evidence)) {
|
if (!SCAN_ALLMATCHES && num_alerts != evidence_num_alerts(ctx->this_layer_evidence)) {
|
||||||
cli_exe_info_destroy(peinfo);
|
cli_exe_info_destroy(peinfo);
|
||||||
return CL_VIRUS;
|
return CL_VIRUS;
|
||||||
}
|
}
|
||||||
|
@ -4699,10 +4658,7 @@ cl_error_t cli_peheader(fmap_t *map, struct cli_exe_info *peinfo, uint32_t opts,
|
||||||
pe_add_heuristic_property(ctx, "BadNumberOfSections");
|
pe_add_heuristic_property(ctx, "BadNumberOfSections");
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Investigate how corrupted_input is set and whether this
|
if ((opts & CLI_PEHEADER_OPT_DBG_PRINT_INFO) && !ctx->corrupted_input) {
|
||||||
// check is needed
|
|
||||||
if (opts & CLI_PEHEADER_OPT_DBG_PRINT_INFO &&
|
|
||||||
!ctx->corrupted_input) {
|
|
||||||
if (peinfo->nsections == 0) {
|
if (peinfo->nsections == 0) {
|
||||||
cli_dbgmsg("cli_peheader: Invalid NumberOfSections (0)\n");
|
cli_dbgmsg("cli_peheader: Invalid NumberOfSections (0)\n");
|
||||||
}
|
}
|
||||||
|
@ -5436,7 +5392,8 @@ cl_error_t cli_peheader(fmap_t *map, struct cli_exe_info *peinfo, uint32_t opts,
|
||||||
} /* look for stringfileinfo - NOT RESUMABLE */
|
} /* look for stringfileinfo - NOT RESUMABLE */
|
||||||
break;
|
break;
|
||||||
} /* look for version_info - NOT RESUMABLE */
|
} /* look for version_info - NOT RESUMABLE */
|
||||||
} /* enum all version_information res - RESUMABLE */
|
|
||||||
|
} /* enum all version_information res - RESUMABLE */
|
||||||
break;
|
break;
|
||||||
} /* while(dirs[2].Size) */
|
} /* while(dirs[2].Size) */
|
||||||
|
|
||||||
|
@ -5495,6 +5452,9 @@ cl_error_t cli_check_auth_header(cli_ctx *ctx, struct cli_exe_info *peinfo)
|
||||||
uint32_t sec_dir_size;
|
uint32_t sec_dir_size;
|
||||||
struct cli_exe_info _peinfo;
|
struct cli_exe_info _peinfo;
|
||||||
|
|
||||||
|
char *source = NULL;
|
||||||
|
size_t source_len = 0;
|
||||||
|
|
||||||
// If Authenticode parsing has been disabled via DCONF or an engine
|
// If Authenticode parsing has been disabled via DCONF or an engine
|
||||||
// option, then don't continue on.
|
// option, then don't continue on.
|
||||||
if (!(DCONF & PE_CONF_CERTS))
|
if (!(DCONF & PE_CONF_CERTS))
|
||||||
|
@ -5525,7 +5485,7 @@ cl_error_t cli_check_auth_header(cli_ctx *ctx, struct cli_exe_info *peinfo)
|
||||||
// for the 'PE' .cat Authenticode hash file type.
|
// for the 'PE' .cat Authenticode hash file type.
|
||||||
if (sec_dir_size < 8 &&
|
if (sec_dir_size < 8 &&
|
||||||
!cli_hm_have_size(ctx->engine->hm_fp, CLI_HASH_SHA1, 2) &&
|
!cli_hm_have_size(ctx->engine->hm_fp, CLI_HASH_SHA1, 2) &&
|
||||||
!cli_hm_have_size(ctx->engine->hm_fp, CLI_HASH_SHA256, 2)) {
|
!cli_hm_have_size(ctx->engine->hm_fp, CLI_HASH_SHA2_256, 2)) {
|
||||||
ret = CL_BREAK;
|
ret = CL_BREAK;
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
@ -5656,7 +5616,7 @@ cl_error_t cli_check_auth_header(cli_ctx *ctx, struct cli_exe_info *peinfo)
|
||||||
const char *hashctx_name;
|
const char *hashctx_name;
|
||||||
} supported_hashes[] = {
|
} supported_hashes[] = {
|
||||||
{CLI_HASH_SHA1, "sha1"},
|
{CLI_HASH_SHA1, "sha1"},
|
||||||
{CLI_HASH_SHA256, "sha256"},
|
{CLI_HASH_SHA2_256, "sha2-256"},
|
||||||
};
|
};
|
||||||
|
|
||||||
for (i = 0; i < (sizeof(supported_hashes) / sizeof(supported_hashes[0])); i++) {
|
for (i = 0; i < (sizeof(supported_hashes) / sizeof(supported_hashes[0])); i++) {
|
||||||
|
@ -5695,6 +5655,20 @@ cl_error_t cli_check_auth_header(cli_ctx *ctx, struct cli_exe_info *peinfo)
|
||||||
|
|
||||||
if (cli_hm_scan(authsha, 2, NULL, ctx->engine->hm_fp, hashtype) == CL_VIRUS) {
|
if (cli_hm_scan(authsha, 2, NULL, ctx->engine->hm_fp, hashtype) == CL_VIRUS) {
|
||||||
cli_dbgmsg("cli_check_auth_header: PE file trusted by catalog file (%s)\n", hashctx_name);
|
cli_dbgmsg("cli_check_auth_header: PE file trusted by catalog file (%s)\n", hashctx_name);
|
||||||
|
|
||||||
|
source_len = strlen("authenticode catalog file: ") + strlen(hashctx_name) + 1;
|
||||||
|
source = malloc(source_len);
|
||||||
|
if (!source) {
|
||||||
|
cli_errmsg("dispatch_scan_callback: no memory for source string\n");
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
snprintf(source, source_len, "authenticode catalog file: %s", hashctx_name);
|
||||||
|
|
||||||
|
// Remove any evidence for this layer and set the verdict to trusted.
|
||||||
|
(void)cli_trust_this_layer(ctx, source);
|
||||||
|
|
||||||
|
CLI_FREE_AND_SET_NULL(source);
|
||||||
|
|
||||||
ret = CL_VERIFIED;
|
ret = CL_VERIFIED;
|
||||||
goto finish;
|
goto finish;
|
||||||
}
|
}
|
||||||
|
@ -5715,10 +5689,13 @@ finish:
|
||||||
if (&_peinfo == peinfo) {
|
if (&_peinfo == peinfo) {
|
||||||
cli_exe_info_destroy(peinfo);
|
cli_exe_info_destroy(peinfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CLI_FREE_AND_SET_NULL(source);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Print out either the MD5, SHA1, or SHA256 associated with the imphash or
|
/* Print out either the MD5, SHA1, or SHA2-256 associated with the imphash or
|
||||||
* the individual sections. Also, this function computes the hashes of each
|
* the individual sections. Also, this function computes the hashes of each
|
||||||
* section (sorted based on the RVAs of the sections) if hashes is non-NULL.
|
* section (sorted based on the RVAs of the sections) if hashes is non-NULL.
|
||||||
*
|
*
|
||||||
|
@ -5737,15 +5714,16 @@ finish:
|
||||||
* - If a section exists completely outside of the file, it won't be included
|
* - If a section exists completely outside of the file, it won't be included
|
||||||
* in the list of sections, and nsections will be adjusted accordingly.
|
* in the list of sections, and nsections will be adjusted accordingly.
|
||||||
*/
|
*/
|
||||||
cl_error_t cli_genhash_pe(cli_ctx *ctx, unsigned int class, int type, stats_section_t *hashes)
|
cl_error_t cli_genhash_pe(cli_ctx *ctx, unsigned int class, cli_hash_type_t type, stats_section_t *hashes)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
struct cli_exe_info _peinfo;
|
struct cli_exe_info _peinfo;
|
||||||
struct cli_exe_info *peinfo = &_peinfo;
|
struct cli_exe_info *peinfo = &_peinfo;
|
||||||
|
|
||||||
unsigned char *hash, *hashset[CLI_HASH_AVAIL_TYPES];
|
uint8_t *hash = NULL;
|
||||||
int genhash[CLI_HASH_AVAIL_TYPES];
|
uint8_t *hashset[CLI_HASH_AVAIL_TYPES] = {NULL};
|
||||||
int hlen = 0;
|
bool genhash[CLI_HASH_AVAIL_TYPES] = {false};
|
||||||
|
int hlen = 0;
|
||||||
|
|
||||||
if (hashes) {
|
if (hashes) {
|
||||||
hashes->sections = NULL;
|
hashes->sections = NULL;
|
||||||
|
@ -5771,26 +5749,16 @@ cl_error_t cli_genhash_pe(cli_ctx *ctx, unsigned int class, int type, stats_sect
|
||||||
cli_qsort(peinfo->sections, peinfo->nsections, sizeof(*(peinfo->sections)), sort_sects);
|
cli_qsort(peinfo->sections, peinfo->nsections, sizeof(*(peinfo->sections)), sort_sects);
|
||||||
|
|
||||||
/* pick hashtypes to generate */
|
/* pick hashtypes to generate */
|
||||||
memset(genhash, 0, sizeof(genhash));
|
genhash[type] = true;
|
||||||
memset(hashset, 0, sizeof(hashset));
|
|
||||||
switch (type) {
|
hlen = cli_hash_len(type);
|
||||||
case 1:
|
if (hlen <= 0) {
|
||||||
genhash[CLI_HASH_MD5] = 1;
|
cli_dbgmsg("cli_genhash_pe: Invalid hash type %u\n", type);
|
||||||
hlen = hashlen[CLI_HASH_MD5];
|
cli_exe_info_destroy(peinfo);
|
||||||
hash = hashset[CLI_HASH_MD5] = calloc(hlen, sizeof(char));
|
return CL_EARG;
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
genhash[CLI_HASH_SHA1] = 1;
|
|
||||||
hlen = hashlen[CLI_HASH_SHA1];
|
|
||||||
hash = hashset[CLI_HASH_SHA1] = calloc(hlen, sizeof(char));
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
genhash[CLI_HASH_SHA256] = 1;
|
|
||||||
hlen = hashlen[CLI_HASH_SHA256];
|
|
||||||
hash = hashset[CLI_HASH_SHA256] = calloc(hlen, sizeof(char));
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hash = hashset[type] = calloc(hlen, sizeof(char));
|
||||||
if (!hash) {
|
if (!hash) {
|
||||||
cli_errmsg("cli_genhash_pe: calloc failed!\n");
|
cli_errmsg("cli_genhash_pe: calloc failed!\n");
|
||||||
cli_exe_info_destroy(peinfo);
|
cli_exe_info_destroy(peinfo);
|
||||||
|
@ -5813,7 +5781,7 @@ cl_error_t cli_genhash_pe(cli_ctx *ctx, unsigned int class, int type, stats_sect
|
||||||
|
|
||||||
for (i = 0; i < peinfo->nsections; i++) {
|
for (i = 0; i < peinfo->nsections; i++) {
|
||||||
/* Generate hashes */
|
/* Generate hashes */
|
||||||
if (cli_hashsect(ctx->fmap, &peinfo->sections[i], hashset, genhash, genhash) == 1) {
|
if (cli_hashsect(ctx->fmap, &peinfo->sections[i], hashset, genhash, genhash)) {
|
||||||
if (cli_debug_flag) {
|
if (cli_debug_flag) {
|
||||||
dstr = cli_str2hex((char *)hash, hlen);
|
dstr = cli_str2hex((char *)hash, hlen);
|
||||||
cli_dbgmsg("Section{%u}: %u:%s\n", i, peinfo->sections[i].rsz, dstr ? (char *)dstr : "(NULL)");
|
cli_dbgmsg("Section{%u}: %u:%s\n", i, peinfo->sections[i].rsz, dstr ? (char *)dstr : "(NULL)");
|
||||||
|
|
|
@ -91,7 +91,7 @@ cl_error_t cli_pe_targetinfo(cli_ctx *ctx, struct cli_exe_info *peinfo);
|
||||||
cl_error_t cli_peheader(fmap_t *map, struct cli_exe_info *peinfo, uint32_t opts, cli_ctx *ctx);
|
cl_error_t cli_peheader(fmap_t *map, struct cli_exe_info *peinfo, uint32_t opts, cli_ctx *ctx);
|
||||||
|
|
||||||
cl_error_t cli_check_auth_header(cli_ctx *ctx, struct cli_exe_info *peinfo);
|
cl_error_t cli_check_auth_header(cli_ctx *ctx, struct cli_exe_info *peinfo);
|
||||||
cl_error_t cli_genhash_pe(cli_ctx *ctx, unsigned int class, int type, stats_section_t *hashes);
|
cl_error_t cli_genhash_pe(cli_ctx *ctx, unsigned int class, cli_hash_type_t type, stats_section_t *hashes);
|
||||||
|
|
||||||
uint32_t cli_rawaddr(uint32_t, const struct cli_exe_section *, uint16_t, unsigned int *, size_t, uint32_t);
|
uint32_t cli_rawaddr(uint32_t, const struct cli_exe_section *, uint16_t, unsigned int *, size_t, uint32_t);
|
||||||
void findres(uint32_t, uint32_t, fmap_t *map, struct cli_exe_info *, int (*)(void *, uint32_t, uint32_t, uint32_t, uint32_t), void *);
|
void findres(uint32_t, uint32_t, fmap_t *map, struct cli_exe_info *, int (*)(void *, uint32_t, uint32_t, uint32_t, uint32_t), void *);
|
||||||
|
|
|
@ -1369,7 +1369,7 @@ static int parseicon(struct ICON_ENV *icon_env, uint32_t rva)
|
||||||
if (!ctx || !ctx->engine || !(matcher = ctx->engine->iconcheck))
|
if (!ctx || !ctx->engine || !(matcher = ctx->engine->iconcheck))
|
||||||
return CL_SUCCESS;
|
return CL_SUCCESS;
|
||||||
map = ctx->fmap;
|
map = ctx->fmap;
|
||||||
tempd = (cli_debug_flag && ctx->engine->keeptmp) ? (ctx->sub_tmpdir ? ctx->sub_tmpdir : cli_gettmpdir()) : NULL;
|
tempd = (cli_debug_flag && ctx->engine->keeptmp) ? (ctx->this_layer_tmpdir ? ctx->this_layer_tmpdir : cli_gettmpdir()) : NULL;
|
||||||
icoff = cli_rawaddr(rva, peinfo->sections, peinfo->nsections, &err, map->len, peinfo->hdr_size);
|
icoff = cli_rawaddr(rva, peinfo->sections, peinfo->nsections, &err, map->len, peinfo->hdr_size);
|
||||||
|
|
||||||
/* read the bitmap header */
|
/* read the bitmap header */
|
||||||
|
|
|
@ -1168,37 +1168,37 @@ static cl_error_t hash_match(const struct regex_matcher* rlist,
|
||||||
|
|
||||||
*phishing_verdict = CL_PHISH_NODECISION;
|
*phishing_verdict = CL_PHISH_NODECISION;
|
||||||
|
|
||||||
if (rlist->sha256_hashes.bm_patterns) {
|
if (rlist->sha2_256_hashes.bm_patterns) {
|
||||||
const char hexchars[] = "0123456789ABCDEF";
|
const char hexchars[] = "0123456789ABCDEF";
|
||||||
unsigned char h[65];
|
unsigned char h[65];
|
||||||
unsigned char sha256_dig[32];
|
unsigned char sha2_256_dig[32];
|
||||||
unsigned i;
|
unsigned i;
|
||||||
void* sha256;
|
void* sha2_256;
|
||||||
|
|
||||||
sha256 = cl_hash_init("sha256");
|
sha2_256 = cl_hash_init("sha2-256");
|
||||||
if (!(sha256))
|
if (!(sha2_256))
|
||||||
return CL_EMEM;
|
return CL_EMEM;
|
||||||
|
|
||||||
cl_update_hash(sha256, (void*)host, hlen);
|
cl_update_hash(sha2_256, (void*)host, hlen);
|
||||||
cl_update_hash(sha256, (void*)path, plen);
|
cl_update_hash(sha2_256, (void*)path, plen);
|
||||||
cl_finish_hash(sha256, sha256_dig);
|
cl_finish_hash(sha2_256, sha2_256_dig);
|
||||||
|
|
||||||
for (i = 0; i < 32; i++) {
|
for (i = 0; i < 32; i++) {
|
||||||
h[2 * i] = hexchars[sha256_dig[i] >> 4];
|
h[2 * i] = hexchars[sha2_256_dig[i] >> 4];
|
||||||
h[2 * i + 1] = hexchars[sha256_dig[i] & 0xf];
|
h[2 * i + 1] = hexchars[sha2_256_dig[i] & 0xf];
|
||||||
}
|
}
|
||||||
h[64] = '\0';
|
h[64] = '\0';
|
||||||
cli_dbgmsg("Looking up hash %s for %s(%u)%s(%u)\n", h, host, (unsigned)hlen, path, (unsigned)plen);
|
cli_dbgmsg("Looking up hash %s for %s(%u)%s(%u)\n", h, host, (unsigned)hlen, path, (unsigned)plen);
|
||||||
#if 0
|
#if 0
|
||||||
if (prefix_matched) {
|
if (prefix_matched) {
|
||||||
if (cli_bm_scanbuff(sha256_dig, 4, &virname, NULL, &rlist->hostkey_prefix,0,NULL,NULL,NULL) == CL_VIRUS) {
|
if (cli_bm_scanbuff(sha2_256_dig, 4, &virname, NULL, &rlist->hostkey_prefix,0,NULL,NULL,NULL) == CL_VIRUS) {
|
||||||
cli_dbgmsg("prefix matched\n");
|
cli_dbgmsg("prefix matched\n");
|
||||||
*prefix_matched = 1;
|
*prefix_matched = 1;
|
||||||
} else
|
} else
|
||||||
return CL_SUCCESS;
|
return CL_SUCCESS;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (cli_bm_scanbuff(sha256_dig, 32, &virname, NULL, &rlist->sha256_hashes, 0, NULL, NULL, NULL) == CL_VIRUS) {
|
if (cli_bm_scanbuff(sha2_256_dig, 32, &virname, NULL, &rlist->sha2_256_hashes, 0, NULL, NULL, NULL) == CL_VIRUS) {
|
||||||
cli_dbgmsg("This hash matched: %s\n", h);
|
cli_dbgmsg("This hash matched: %s\n", h);
|
||||||
switch (*virname) {
|
switch (*virname) {
|
||||||
case 'W':
|
case 'W':
|
||||||
|
@ -1347,7 +1347,7 @@ static cl_error_t url_hash_match(
|
||||||
char urlbuff[URL_MAX_LEN + 3]; /* htmlnorm truncates at 1024 bytes + terminating null + slash + host end null */
|
char urlbuff[URL_MAX_LEN + 3]; /* htmlnorm truncates at 1024 bytes + terminating null + slash + host end null */
|
||||||
unsigned count;
|
unsigned count;
|
||||||
|
|
||||||
if (!rlist || !rlist->sha256_hashes.bm_patterns) {
|
if (!rlist || !rlist->sha2_256_hashes.bm_patterns) {
|
||||||
/* no hashes loaded -> don't waste time canonicalizing and
|
/* no hashes loaded -> don't waste time canonicalizing and
|
||||||
* looking up */
|
* looking up */
|
||||||
goto done;
|
goto done;
|
||||||
|
|
|
@ -2615,7 +2615,7 @@ static int cli_loadinfo(FILE *fs, struct cl_engine *engine, unsigned int options
|
||||||
return CL_EMALFDB;
|
return CL_EMALFDB;
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx = cl_hash_init("sha256");
|
ctx = cl_hash_init("sha2-256");
|
||||||
if (!(ctx))
|
if (!(ctx))
|
||||||
return CL_EMALFDB;
|
return CL_EMALFDB;
|
||||||
|
|
||||||
|
@ -2695,7 +2695,7 @@ static int cli_loadinfo(FILE *fs, struct cl_engine *engine, unsigned int options
|
||||||
new->size = atoi(tokens[1]);
|
new->size = atoi(tokens[1]);
|
||||||
|
|
||||||
if (strlen(tokens[2]) != 64 || !(new->hash = CLI_MPOOL_HEX2STR(engine->mempool, tokens[2]))) {
|
if (strlen(tokens[2]) != 64 || !(new->hash = CLI_MPOOL_HEX2STR(engine->mempool, tokens[2]))) {
|
||||||
cli_errmsg("cli_loadinfo: Malformed SHA256 string at line %u\n", line);
|
cli_errmsg("cli_loadinfo: Malformed SHA2-256 string at line %u\n", line);
|
||||||
MPOOL_FREE(engine->mempool, new->name);
|
MPOOL_FREE(engine->mempool, new->name);
|
||||||
MPOOL_FREE(engine->mempool, new);
|
MPOOL_FREE(engine->mempool, new);
|
||||||
ret = CL_EMALFDB;
|
ret = CL_EMALFDB;
|
||||||
|
@ -2820,48 +2820,20 @@ static int cli_loadign(FILE *fs, struct cl_engine *engine, unsigned int options,
|
||||||
return CL_SUCCESS;
|
return CL_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define MD5_HDB 0
|
#define HASH_DB_TOKENS 5
|
||||||
#define MD5_MDB 1
|
static int cli_loadhash(FILE *fs, struct cl_engine *engine, unsigned int *signo, hash_purpose_t purpose, unsigned int options, struct cli_dbio *dbio, const char *dbname)
|
||||||
#define MD5_FP 2
|
|
||||||
#define MD5_IMP 3
|
|
||||||
|
|
||||||
#define MD5_TOKENS 5
|
|
||||||
static int cli_loadhash(FILE *fs, struct cl_engine *engine, unsigned int *signo, unsigned int mode, unsigned int options, struct cli_dbio *dbio, const char *dbname)
|
|
||||||
{
|
{
|
||||||
const char *tokens[MD5_TOKENS + 1];
|
const char *tokens[HASH_DB_TOKENS + 1];
|
||||||
char buffer[FILEBUFF], *buffer_cpy = NULL;
|
char buffer[FILEBUFF], *buffer_cpy = NULL;
|
||||||
const char *pt, *virname;
|
const char *pt, *virname;
|
||||||
int ret = CL_SUCCESS;
|
int ret = CL_SUCCESS;
|
||||||
unsigned int size_field = 1, md5_field = 0, line = 0, sigs = 0, tokens_count;
|
unsigned int size_field = 1, hash_field = 0, line = 0, sigs = 0, tokens_count;
|
||||||
unsigned int req_fl = 0;
|
unsigned int req_fl = 0;
|
||||||
struct cli_matcher *db;
|
|
||||||
unsigned long size;
|
unsigned long size;
|
||||||
|
|
||||||
if (mode == MD5_MDB) {
|
if (purpose == HASH_PURPOSE_PE_SECTION_DETECT) {
|
||||||
size_field = 0;
|
size_field = 0;
|
||||||
md5_field = 1;
|
hash_field = 1;
|
||||||
db = engine->hm_mdb;
|
|
||||||
} else if (mode == MD5_HDB)
|
|
||||||
db = engine->hm_hdb;
|
|
||||||
else if (mode == MD5_IMP)
|
|
||||||
db = engine->hm_imp;
|
|
||||||
else
|
|
||||||
db = engine->hm_fp;
|
|
||||||
|
|
||||||
if (!db) {
|
|
||||||
if (!(db = MPOOL_CALLOC(engine->mempool, 1, sizeof(*db))))
|
|
||||||
return CL_EMEM;
|
|
||||||
#ifdef USE_MPOOL
|
|
||||||
db->mempool = engine->mempool;
|
|
||||||
#endif
|
|
||||||
if (mode == MD5_HDB)
|
|
||||||
engine->hm_hdb = db;
|
|
||||||
else if (mode == MD5_MDB)
|
|
||||||
engine->hm_mdb = db;
|
|
||||||
else if (mode == MD5_IMP)
|
|
||||||
engine->hm_imp = db;
|
|
||||||
else
|
|
||||||
engine->hm_fp = db;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (engine->ignored)
|
if (engine->ignored)
|
||||||
|
@ -2878,23 +2850,23 @@ static int cli_loadhash(FILE *fs, struct cl_engine *engine, unsigned int *signo,
|
||||||
if (engine->ignored)
|
if (engine->ignored)
|
||||||
strcpy(buffer_cpy, buffer);
|
strcpy(buffer_cpy, buffer);
|
||||||
|
|
||||||
tokens_count = cli_strtokenize(buffer, ':', MD5_TOKENS + 1, tokens);
|
tokens_count = cli_strtokenize(buffer, ':', HASH_DB_TOKENS + 1, tokens);
|
||||||
if (tokens_count < 3) {
|
if (tokens_count < 3) {
|
||||||
ret = CL_EMALFDB;
|
ret = CL_EMALFDB;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (tokens_count > MD5_TOKENS - 2) {
|
if (tokens_count > HASH_DB_TOKENS - 2) {
|
||||||
req_fl = atoi(tokens[MD5_TOKENS - 2]);
|
req_fl = atoi(tokens[HASH_DB_TOKENS - 2]);
|
||||||
|
|
||||||
if (tokens_count > MD5_TOKENS) {
|
if (tokens_count > HASH_DB_TOKENS) {
|
||||||
ret = CL_EMALFDB;
|
ret = CL_EMALFDB;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cl_retflevel() < req_fl)
|
if (cl_retflevel() < req_fl)
|
||||||
continue;
|
continue;
|
||||||
if (tokens_count == MD5_TOKENS) {
|
if (tokens_count == HASH_DB_TOKENS) {
|
||||||
int max_fl = atoi(tokens[MD5_TOKENS - 1]);
|
int max_fl = atoi(tokens[HASH_DB_TOKENS - 1]);
|
||||||
if (cl_retflevel() > (unsigned int)max_fl)
|
if (cl_retflevel() > (unsigned int)max_fl)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -2914,7 +2886,7 @@ static int cli_loadhash(FILE *fs, struct cl_engine *engine, unsigned int *signo,
|
||||||
// is specified. This check doesn't apply to .imp rules, though,
|
// is specified. This check doesn't apply to .imp rules, though,
|
||||||
// since this rule category wasn't introduced until FLEVEL 90, and
|
// since this rule category wasn't introduced until FLEVEL 90, and
|
||||||
// has always supported wildcard usage in rules.
|
// has always supported wildcard usage in rules.
|
||||||
if (mode != MD5_IMP && ((tokens_count < MD5_TOKENS - 1) || (req_fl < 73))) {
|
if (purpose != HASH_PURPOSE_PE_IMPORT_DETECT && ((tokens_count < HASH_DB_TOKENS - 1) || (req_fl < 73))) {
|
||||||
cli_errmsg("cli_loadhash: Minimum FLEVEL field must be at least 73 for wildcard size hash signatures."
|
cli_errmsg("cli_loadhash: Minimum FLEVEL field must be at least 73 for wildcard size hash signatures."
|
||||||
" For reference, running FLEVEL is %d\n",
|
" For reference, running FLEVEL is %d\n",
|
||||||
cl_retflevel());
|
cl_retflevel());
|
||||||
|
@ -2949,7 +2921,7 @@ static int cli_loadhash(FILE *fs, struct cl_engine *engine, unsigned int *signo,
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CL_SUCCESS != (ret = hm_addhash_str(db, tokens[md5_field], size, virname))) {
|
if (CL_SUCCESS != (ret = hm_addhash_str(engine, purpose, tokens[hash_field], size, virname))) {
|
||||||
cli_errmsg("cli_loadhash: Malformed hash string at line %u\n", line);
|
cli_errmsg("cli_loadhash: Malformed hash string at line %u\n", line);
|
||||||
MPOOL_FREE(engine->mempool, (void *)virname);
|
MPOOL_FREE(engine->mempool, (void *)virname);
|
||||||
break;
|
break;
|
||||||
|
@ -3536,7 +3508,7 @@ static int cli_loadmscat(FILE *fs, const char *dbname, struct cl_engine *engine,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(map = fmap(fileno(fs), 0, 0, dbname))) {
|
if (!(map = fmap_new(fileno(fs), 0, 0, dbname, NULL))) {
|
||||||
cli_dbgmsg("Can't map cat: %s\n", dbname);
|
cli_dbgmsg("Can't map cat: %s\n", dbname);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -3545,7 +3517,7 @@ static int cli_loadmscat(FILE *fs, const char *dbname, struct cl_engine *engine,
|
||||||
cli_dbgmsg("Failed to load certificates from cat: %s\n", dbname);
|
cli_dbgmsg("Failed to load certificates from cat: %s\n", dbname);
|
||||||
}
|
}
|
||||||
|
|
||||||
funmap(map);
|
fmap_free(map);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4776,35 +4748,35 @@ cl_error_t cli_load(const char *filename, struct cl_engine *engine, unsigned int
|
||||||
ret = cli_loaddb(fs, engine, signo, options, dbio, dbname);
|
ret = cli_loaddb(fs, engine, signo, options, dbio, dbname);
|
||||||
|
|
||||||
} else if (cli_strbcasestr(dbname, ".cvd")) {
|
} else if (cli_strbcasestr(dbname, ".cvd")) {
|
||||||
ret = cli_cvdload(engine, signo, options, CVD_TYPE_CVD, filename, sign_verifier, 0);
|
ret = cli_cvdload(engine, signo, options, CVD_TYPE_CVD, filename, sign_verifier, false);
|
||||||
|
|
||||||
} else if (cli_strbcasestr(dbname, ".cld")) {
|
} else if (cli_strbcasestr(dbname, ".cld")) {
|
||||||
ret = cli_cvdload(engine, signo, options, CVD_TYPE_CLD, filename, sign_verifier, 0);
|
ret = cli_cvdload(engine, signo, options, CVD_TYPE_CLD, filename, sign_verifier, false);
|
||||||
|
|
||||||
} else if (cli_strbcasestr(dbname, ".cud")) {
|
} else if (cli_strbcasestr(dbname, ".cud")) {
|
||||||
ret = cli_cvdload(engine, signo, options, CVD_TYPE_CUD, filename, sign_verifier, 0);
|
ret = cli_cvdload(engine, signo, options, CVD_TYPE_CUD, filename, sign_verifier, false);
|
||||||
|
|
||||||
} else if (cli_strbcasestr(dbname, ".crb")) {
|
} else if (cli_strbcasestr(dbname, ".crb")) {
|
||||||
ret = cli_loadcrt(fs, engine, dbio);
|
ret = cli_loadcrt(fs, engine, dbio);
|
||||||
|
|
||||||
} else if (cli_strbcasestr(dbname, ".hdb") || cli_strbcasestr(dbname, ".hsb")) {
|
} else if (cli_strbcasestr(dbname, ".hdb") || cli_strbcasestr(dbname, ".hsb")) {
|
||||||
ret = cli_loadhash(fs, engine, signo, MD5_HDB, options, dbio, dbname);
|
ret = cli_loadhash(fs, engine, signo, HASH_PURPOSE_WHOLE_FILE_DETECT, options, dbio, dbname);
|
||||||
} else if (cli_strbcasestr(dbname, ".hdu") || cli_strbcasestr(dbname, ".hsu")) {
|
} else if (cli_strbcasestr(dbname, ".hdu") || cli_strbcasestr(dbname, ".hsu")) {
|
||||||
if (options & CL_DB_PUA)
|
if (options & CL_DB_PUA)
|
||||||
ret = cli_loadhash(fs, engine, signo, MD5_HDB, options | CL_DB_PUA_MODE, dbio, dbname);
|
ret = cli_loadhash(fs, engine, signo, HASH_PURPOSE_WHOLE_FILE_DETECT, options | CL_DB_PUA_MODE, dbio, dbname);
|
||||||
else
|
else
|
||||||
skipped = 1;
|
skipped = 1;
|
||||||
|
|
||||||
} else if (cli_strbcasestr(dbname, ".fp") || cli_strbcasestr(dbname, ".sfp")) {
|
} else if (cli_strbcasestr(dbname, ".fp") || cli_strbcasestr(dbname, ".sfp")) {
|
||||||
ret = cli_loadhash(fs, engine, signo, MD5_FP, options, dbio, dbname);
|
ret = cli_loadhash(fs, engine, signo, HASH_PURPOSE_WHOLE_FILE_FP_CHECK, options, dbio, dbname);
|
||||||
} else if (cli_strbcasestr(dbname, ".mdb") || cli_strbcasestr(dbname, ".msb")) {
|
} else if (cli_strbcasestr(dbname, ".mdb") || cli_strbcasestr(dbname, ".msb")) {
|
||||||
ret = cli_loadhash(fs, engine, signo, MD5_MDB, options, dbio, dbname);
|
ret = cli_loadhash(fs, engine, signo, HASH_PURPOSE_PE_SECTION_DETECT, options, dbio, dbname);
|
||||||
} else if (cli_strbcasestr(dbname, ".imp")) {
|
} else if (cli_strbcasestr(dbname, ".imp")) {
|
||||||
ret = cli_loadhash(fs, engine, signo, MD5_IMP, options, dbio, dbname);
|
ret = cli_loadhash(fs, engine, signo, HASH_PURPOSE_PE_IMPORT_DETECT, options, dbio, dbname);
|
||||||
|
|
||||||
} else if (cli_strbcasestr(dbname, ".mdu") || cli_strbcasestr(dbname, ".msu")) {
|
} else if (cli_strbcasestr(dbname, ".mdu") || cli_strbcasestr(dbname, ".msu")) {
|
||||||
if (options & CL_DB_PUA)
|
if (options & CL_DB_PUA)
|
||||||
ret = cli_loadhash(fs, engine, signo, MD5_MDB, options | CL_DB_PUA_MODE, dbio, dbname);
|
ret = cli_loadhash(fs, engine, signo, HASH_PURPOSE_PE_SECTION_DETECT, options | CL_DB_PUA_MODE, dbio, dbname);
|
||||||
else
|
else
|
||||||
skipped = 1;
|
skipped = 1;
|
||||||
|
|
||||||
|
@ -5289,7 +5261,7 @@ cl_error_t cl_load(const char *path, struct cl_engine *engine, unsigned int *sig
|
||||||
}
|
}
|
||||||
|
|
||||||
if (engine->dboptions & CL_DB_COMPILED) {
|
if (engine->dboptions & CL_DB_COMPILED) {
|
||||||
cli_errmsg("cl_load(): can't load new databases when engine is already compiled\n");
|
cli_errmsg("cl_load: can't load new databases when engine is already compiled\n");
|
||||||
return CL_EARG;
|
return CL_EARG;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5297,27 +5269,27 @@ cl_error_t cl_load(const char *path, struct cl_engine *engine, unsigned int *sig
|
||||||
switch (errno) {
|
switch (errno) {
|
||||||
#if defined(EACCES)
|
#if defined(EACCES)
|
||||||
case EACCES:
|
case EACCES:
|
||||||
cli_errmsg("cl_load(): Access denied for path: %s\n", path);
|
cli_errmsg("cl_load: Access denied for path: %s\n", path);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#if defined(ENOENT)
|
#if defined(ENOENT)
|
||||||
case ENOENT:
|
case ENOENT:
|
||||||
cli_errmsg("cl_load(): No such file or directory: %s\n", path);
|
cli_errmsg("cl_load: No such file or directory: %s\n", path);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#if defined(ELOOP)
|
#if defined(ELOOP)
|
||||||
case ELOOP:
|
case ELOOP:
|
||||||
cli_errmsg("cl_load(): Too many symbolic links encountered in path: %s\n", path);
|
cli_errmsg("cl_load: Too many symbolic links encountered in path: %s\n", path);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#if defined(EOVERFLOW)
|
#if defined(EOVERFLOW)
|
||||||
case EOVERFLOW:
|
case EOVERFLOW:
|
||||||
cli_errmsg("cl_load(): File size is too large to be recognized. Path: %s\n", path);
|
cli_errmsg("cl_load: File size is too large to be recognized. Path: %s\n", path);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#if defined(EIO)
|
#if defined(EIO)
|
||||||
case EIO:
|
case EIO:
|
||||||
cli_errmsg("cl_load(): An I/O error occurred while reading from path: %s\n", path);
|
cli_errmsg("cl_load: An I/O error occurred while reading from path: %s\n", path);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
default:
|
default:
|
||||||
|
@ -5338,8 +5310,13 @@ cl_error_t cl_load(const char *path, struct cl_engine *engine, unsigned int *sig
|
||||||
cli_dbgmsg("Bytecode engine disabled\n");
|
cli_dbgmsg("Bytecode engine disabled\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!engine->cache && clean_cache_init(engine))
|
if (!engine->cache) {
|
||||||
return CL_EMEM;
|
ret = clean_cache_init(engine);
|
||||||
|
if (ret != CL_SUCCESS) {
|
||||||
|
cli_errmsg("cl_load: Failed to initialize the cache: %s\n", cl_strerror(ret));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
engine->dboptions |= dboptions;
|
engine->dboptions |= dboptions;
|
||||||
|
|
||||||
|
@ -5365,7 +5342,7 @@ cl_error_t cl_load(const char *path, struct cl_engine *engine, unsigned int *sig
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
cli_errmsg("cl_load(%s): Not supported database file type\n", path);
|
cli_errmsg("cl_load: Not supported database file type: %s\n", path);
|
||||||
if (sign_verifier) {
|
if (sign_verifier) {
|
||||||
codesign_verifier_free(sign_verifier);
|
codesign_verifier_free(sign_verifier);
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue