mirror of
https://github.com/gentoo-mirror/gentoo.git
synced 2026-08-24 18:58:08 -07:00
app-antivirus/clamav: backport security fixes from v1.0.9
Signed-off-by: Michael Orlitzky <mjo@gentoo.org>
This commit is contained in:
239
app-antivirus/clamav/clamav-0.103.12-r2.ebuild
Normal file
239
app-antivirus/clamav/clamav-0.103.12-r2.ebuild
Normal file
@@ -0,0 +1,239 @@
|
||||
# Copyright 1999-2025 Gentoo Authors
|
||||
# Distributed under the terms of the GNU General Public License v2
|
||||
|
||||
EAPI=8
|
||||
|
||||
inherit autotools flag-o-matic systemd tmpfiles
|
||||
|
||||
DESCRIPTION="Clam Anti-Virus Scanner"
|
||||
HOMEPAGE="https://www.clamav.net/"
|
||||
SRC_URI="https://www.clamav.net/downloads/production/${P}.tar.gz"
|
||||
|
||||
LICENSE="GPL-2 unRAR"
|
||||
SLOT="0/lts"
|
||||
KEYWORDS="~alpha ~amd64 ~arm ~arm64 ~hppa ~ppc ~ppc64 ~riscv ~sparc ~x86 ~amd64-linux ~x86-linux ~ppc-macos"
|
||||
IUSE="bzip2 doc clamonacc clamdtop clamsubmit iconv libclamav-only milter metadata-analysis-api selinux systemd test xml"
|
||||
|
||||
REQUIRED_USE="libclamav-only? ( !clamonacc !clamdtop !clamsubmit !milter !metadata-analysis-api )"
|
||||
|
||||
RESTRICT="!test? ( test )"
|
||||
|
||||
# Require acct-{user,group}/clamav at build time so that we can set
|
||||
# the permissions on /var/lib/clamav in src_install rather than in
|
||||
# pkg_postinst; calling "chown" on the live filesystem scares me.
|
||||
CDEPEND="acct-group/clamav
|
||||
acct-user/clamav
|
||||
dev-libs/libltdl
|
||||
dev-libs/libmspack
|
||||
|| ( dev-libs/libpcre2 >dev-libs/libpcre-6 )
|
||||
dev-libs/tomsfastmath
|
||||
>=sys-libs/zlib-1.2.2:=
|
||||
bzip2? ( app-arch/bzip2 )
|
||||
clamdtop? ( sys-libs/ncurses:0 )
|
||||
clamsubmit? ( net-misc/curl dev-libs/json-c:= )
|
||||
elibc_musl? ( sys-libs/fts-standalone )
|
||||
iconv? ( virtual/libiconv )
|
||||
!libclamav-only? ( net-misc/curl )
|
||||
dev-libs/openssl:0=
|
||||
milter? ( mail-filter/libmilter:= )
|
||||
xml? ( dev-libs/libxml2:= )"
|
||||
|
||||
# We need at least autoconf-2.69-r5 because that's the first (patched)
|
||||
# version of it in Gentoo that supports ./configure --runstatedir.
|
||||
BDEPEND=">=dev-build/autoconf-2.69-r5
|
||||
virtual/pkgconfig"
|
||||
|
||||
DEPEND="${CDEPEND}
|
||||
metadata-analysis-api? ( dev-libs/json-c:* )
|
||||
test? ( dev-libs/check )"
|
||||
RDEPEND="${CDEPEND}
|
||||
selinux? ( sec-policy/selinux-clamav )"
|
||||
|
||||
PATCHES=(
|
||||
"${FILESDIR}/${PN}-0.102.1-libxml2_pkgconfig.patch" #661328
|
||||
"${FILESDIR}/${PN}-0.102.2-fix-curl-detection.patch" #709616
|
||||
"${FILESDIR}/${PN}-0.103.0-system-tomsfastmath.patch" # 649394
|
||||
"${FILESDIR}/${PN}-0.103.1-upstream-openrc.patch"
|
||||
"${FILESDIR}/${PN}-0.103.12-missing-const.patch"
|
||||
"${FILESDIR}/${PN}-0.103.12-fix-lzma-uaf.patch"
|
||||
"${FILESDIR}/${PN}-0.103.12-cve-2025-20260.patch"
|
||||
)
|
||||
|
||||
src_prepare() {
|
||||
default
|
||||
|
||||
# Be extra sure that we're using the system copy of tomsfastmath
|
||||
einfo "removing bundled copy of dev-libs/tomsfastmath"
|
||||
rm -r libclamav/tomsfastmath || \
|
||||
die "failed to remove bundled tomsfastmath"
|
||||
|
||||
AT_NO_RECURSIVE="yes" eautoreconf
|
||||
}
|
||||
|
||||
src_configure() {
|
||||
use elibc_musl && append-ldflags -lfts
|
||||
use ppc64 && append-flags -mminimal-toc
|
||||
|
||||
# according to configure help it should be
|
||||
# $(use_enable xml)
|
||||
# but that does not work
|
||||
# do not add this, since --disable-xml seems to override
|
||||
# --without-xml
|
||||
JSONUSE="--without-libjson"
|
||||
|
||||
if use clamsubmit || use metadata-analysis-api; then
|
||||
# either of those 2 requires libjson.
|
||||
# clamsubmit will be built as soon as libjson and curl are found
|
||||
# but we only install the binary if requested
|
||||
JSONUSE="--with-libjson=${EPREFIX}/usr"
|
||||
fi
|
||||
|
||||
local myeconfargs=(
|
||||
$(use_enable bzip2)
|
||||
$(use_enable clamonacc)
|
||||
$(use_enable clamdtop)
|
||||
$(use_enable milter)
|
||||
$(use_enable test check)
|
||||
$(use_with xml)
|
||||
$(use_with iconv)
|
||||
${JSONUSE}
|
||||
$(use_enable libclamav-only)
|
||||
$(use_with !libclamav-only libcurl)
|
||||
--enable-ipv6
|
||||
--with-system-libmspack
|
||||
--cache-file="${S}"/config.cache
|
||||
--disable-experimental
|
||||
--disable-static
|
||||
--disable-zlib-vcheck
|
||||
--enable-id-check
|
||||
--with-dbdir="${EPREFIX}"/var/lib/clamav
|
||||
# Don't call --with-zlib=/usr (see bug #699296)
|
||||
--with-zlib
|
||||
--disable-llvm
|
||||
--enable-openrc
|
||||
--runstatedir=/run
|
||||
)
|
||||
econf "${myeconfargs[@]}"
|
||||
}
|
||||
|
||||
src_install() {
|
||||
default
|
||||
|
||||
rm -rf "${ED}"/var/lib/clamav || die
|
||||
|
||||
if ! use libclamav-only ; then
|
||||
if use systemd; then
|
||||
# The tmpfiles entry is behind USE=systemd because the
|
||||
# OpenRC service scripts should (and do) ensure that the
|
||||
# directories they need exist and have the correct
|
||||
# permissions without the help of tmpfiles.
|
||||
newtmpfiles "${FILESDIR}/tmpfiles.d/clamav-r1.conf" clamav.conf
|
||||
systemd_newunit "${FILESDIR}/clamd_at.service" "clamd@.service"
|
||||
systemd_dounit "${FILESDIR}/clamd.service"
|
||||
systemd_newunit "${FILESDIR}/freshclamd.service-r1" \
|
||||
"freshclamd.service"
|
||||
fi
|
||||
|
||||
insinto /etc/logrotate.d
|
||||
newins "${FILESDIR}/clamd.logrotate" clamd
|
||||
newins "${FILESDIR}/freshclam.logrotate" freshclam
|
||||
use milter && \
|
||||
newins "${FILESDIR}/clamav-milter.logrotate-r1" clamav-milter
|
||||
|
||||
# Modify /etc/{clamd,freshclam}.conf to be usable out of the box
|
||||
sed -i -e "s:^\(Example\):\# \1:" \
|
||||
-e "s/^#\(PidFile .*\)/\1/" \
|
||||
-e "s/^#\(LocalSocket .*\)/\1/" \
|
||||
-e "s/^#\(User .*\)/\1/" \
|
||||
-e "s:^\#\(LogFile\) .*:\1 ${EPREFIX}/var/log/clamav/clamd.log:" \
|
||||
-e "s:^\#\(LogTime\).*:\1 yes:" \
|
||||
-e "s/^#\(DatabaseDirectory .*\)/\1/" \
|
||||
"${ED}"/etc/clamd.conf.sample || die
|
||||
|
||||
sed -i -e "s:^\(Example\):\# \1:" \
|
||||
-e "s/^#\(PidFile .*\)/\1/" \
|
||||
-e "s/^#\(DatabaseOwner .*\)/\1/" \
|
||||
-e "s:^\#\(UpdateLogFile\) .*:\1 ${EPREFIX}/var/log/clamav/freshclam.log:" \
|
||||
-e "s:^\#\(NotifyClamd\).*:\1 ${EPREFIX}/etc/clamd.conf:" \
|
||||
-e "s:^\#\(ScriptedUpdates\).*:\1 yes:" \
|
||||
-e "s/^#\(DatabaseDirectory .*\)/\1/" \
|
||||
"${ED}"/etc/freshclam.conf.sample || die
|
||||
|
||||
if use milter ; then
|
||||
# Note: only keep the "unix" ClamdSocket and MilterSocket!
|
||||
sed -i -e "s:^\(Example\):\# \1:" \
|
||||
-e "s/^#\(PidFile .*\)/\1/" \
|
||||
-e "s/^#\(ClamdSocket unix:.*\)/\1/" \
|
||||
-e "s/^#\(User .*\)/\1/" \
|
||||
-e "s/^#\(MilterSocket unix:.*\)/\1/" \
|
||||
-e "s:^\#\(LogFile\) .*:\1 ${EPREFIX}/var/log/clamav/clamav-milter.log:" \
|
||||
"${ED}"/etc/clamav-milter.conf.sample || die
|
||||
|
||||
cat >> "${ED}"/etc/conf.d/clamd <<-EOF
|
||||
MILTER_NICELEVEL=19
|
||||
START_MILTER=no
|
||||
EOF
|
||||
|
||||
systemd_newunit "${FILESDIR}/clamav-milter.service-r1" clamav-milter.service
|
||||
fi
|
||||
|
||||
local i
|
||||
for i in clamd freshclam clamav-milter
|
||||
do
|
||||
if [[ -f "${ED}"/etc/"${i}".conf.sample ]]; then
|
||||
mv "${ED}"/etc/"${i}".conf{.sample,} || die
|
||||
fi
|
||||
done
|
||||
|
||||
# These both need to be writable by the clamav user.
|
||||
# TODO: use syslog by default; that's what it's for.
|
||||
diropts -o clamav -g clamav
|
||||
keepdir /var/lib/clamav
|
||||
keepdir /var/log/clamav
|
||||
fi
|
||||
|
||||
if use doc ; then
|
||||
local HTML_DOCS=( docs/html/. )
|
||||
einstalldocs
|
||||
|
||||
if ! use libclamav-only ; then
|
||||
doman docs/man/*.[1-8]
|
||||
fi
|
||||
fi
|
||||
|
||||
find "${ED}" -name '*.la' -delete || die
|
||||
}
|
||||
|
||||
src_test() {
|
||||
if use libclamav-only ; then
|
||||
ewarn "Test target not available when USE=libclamav-only is set, skipping tests ..."
|
||||
return 0
|
||||
fi
|
||||
|
||||
emake quick-check
|
||||
}
|
||||
|
||||
pkg_postinst() {
|
||||
if ! use libclamav-only ; then
|
||||
if use systemd ; then
|
||||
tmpfiles_process clamav.conf
|
||||
fi
|
||||
fi
|
||||
|
||||
if use milter ; then
|
||||
elog "For simple instructions how to setup the clamav-milter read the"
|
||||
elog "clamav-milter.README.gentoo in /usr/share/doc/${PF}"
|
||||
fi
|
||||
|
||||
local databases=( "${EROOT}"/var/lib/clamav/main.c[lv]d )
|
||||
if [[ ! -f "${databases}" ]] ; then
|
||||
ewarn "You must run freshclam manually to populate the virus database"
|
||||
ewarn "before starting clamav for the first time."
|
||||
fi
|
||||
|
||||
ewarn "This version of ClamAV provides separate OpenRC services"
|
||||
ewarn "for clamd, freshclam, clamav-milter, and clamonacc. The"
|
||||
ewarn "clamd service now starts only the clamd daemon itself. You"
|
||||
ewarn "should add freshclam (and perhaps clamav-milter) to any"
|
||||
ewarn "runlevels that previously contained clamd."
|
||||
}
|
||||
341
app-antivirus/clamav/files/clamav-0.103.12-cve-2025-20260.patch
Normal file
341
app-antivirus/clamav/files/clamav-0.103.12-cve-2025-20260.patch
Normal file
@@ -0,0 +1,341 @@
|
||||
Taken from
|
||||
|
||||
https://github.com/Cisco-Talos/clamav/commit/fb541aed643
|
||||
|
||||
and applied with a little fuzz to the 0.103.x branch. The bug is not
|
||||
actually exploitable on 0.103.x (according to the release notes), but
|
||||
we might as well apply the readily-available fix.
|
||||
|
||||
diff --git a/libclamav/pdf.c b/libclamav/pdf.c
|
||||
index b8135f6..fe50146 100644
|
||||
--- a/libclamav/pdf.c
|
||||
+++ b/libclamav/pdf.c
|
||||
@@ -441,7 +441,7 @@ int pdf_findobj_in_objstm(struct pdf_struct *pdf, struct objstm_struct *objstm,
|
||||
|
||||
if (CL_SUCCESS != cli_strntol_wrap(index, bytes_remaining, 0, 10, &temp_long)) {
|
||||
/* Failed to find obj offset for next obj */
|
||||
- cli_dbgmsg("pdf_findobj_in_objstm: Failed to find next obj offset for obj in object stream though there should be {%u} more.\n", objstm->n - objstm->nobjs_found);
|
||||
+ cli_dbgmsg("pdf_findobj_in_objstm: Failed to find next obj offset for obj in object stream though there should be {%zu} more.\n", objstm->n - objstm->nobjs_found);
|
||||
status = CL_EPARSE;
|
||||
goto done;
|
||||
} else if (temp_long < 0) {
|
||||
@@ -1551,18 +1551,18 @@ cl_error_t pdf_extract_obj(struct pdf_struct *pdf, struct pdf_obj *obj, uint32_t
|
||||
}
|
||||
}
|
||||
|
||||
- cli_dbgmsg("pdf_extract_obj: calculated length %lld\n", (long long)length);
|
||||
+ cli_dbgmsg("pdf_extract_obj: calculated length %zu\n", length);
|
||||
} else {
|
||||
if (obj->stream_size > (size_t)length + 2) {
|
||||
cli_dbgmsg("cli_pdf: calculated length %zu < %zu\n",
|
||||
- (size_t)length, obj->stream_size);
|
||||
+ length, obj->stream_size);
|
||||
length = obj->stream_size;
|
||||
}
|
||||
}
|
||||
|
||||
- if ((0 != orig_length) && (obj->stream_size > (size_t)orig_length + 20)) {
|
||||
- cli_dbgmsg("pdf_extract_obj: orig length: %lld, length: %lld, size: %zu\n",
|
||||
- (long long)orig_length, (long long)length, obj->stream_size);
|
||||
+ if ((0 != orig_length) && (obj->stream_size > orig_length + 20)) {
|
||||
+ cli_dbgmsg("pdf_extract_obj: orig length: %zu, length: %zu, size: %zu\n",
|
||||
+ orig_length, length, obj->stream_size);
|
||||
pdfobj_flag(pdf, obj, BAD_STREAMLEN);
|
||||
}
|
||||
|
||||
@@ -1613,18 +1613,18 @@ cl_error_t pdf_extract_obj(struct pdf_struct *pdf, struct pdf_obj *obj, uint32_t
|
||||
*/
|
||||
dict_len = obj->stream - start;
|
||||
if (NULL != (pstr = pdf_getdict(start, &dict_len, "/Type/ObjStm"))) {
|
||||
- int32_t objstm_first = -1;
|
||||
- int32_t objstm_length = -1;
|
||||
- int32_t objstm_n = -1;
|
||||
+ int objstm_first = -1;
|
||||
+ int objstm_length = -1;
|
||||
+ int objstm_n = -1;
|
||||
|
||||
cli_dbgmsg("pdf_extract_obj: Found /Type/ObjStm\n");
|
||||
|
||||
dict_len = obj->stream - start;
|
||||
- if ((-1 == (objstm_first = pdf_readint(start, dict_len, "/First")))) {
|
||||
+ if (-1 == (objstm_first = pdf_readint(start, dict_len, "/First"))) {
|
||||
cli_warnmsg("pdf_extract_obj: Failed to find offset of first object in object stream\n");
|
||||
- } else if ((-1 == (objstm_length = pdf_readint(start, dict_len, "/Length")))) {
|
||||
+ } else if (-1 == (objstm_length = pdf_readint(start, dict_len, "/Length"))) {
|
||||
cli_warnmsg("pdf_extract_obj: Failed to find length of object stream\n");
|
||||
- } else if ((-1 == (objstm_n = pdf_readint(start, dict_len, "/N")))) {
|
||||
+ } else if (-1 == (objstm_n = pdf_readint(start, dict_len, "/N"))) {
|
||||
cli_warnmsg("pdf_extract_obj: Failed to find num objects in object stream\n");
|
||||
} else {
|
||||
/* Add objstm to pdf struct, so it can be freed eventually */
|
||||
@@ -1646,19 +1646,19 @@ cl_error_t pdf_extract_obj(struct pdf_struct *pdf, struct pdf_obj *obj, uint32_t
|
||||
|
||||
memset(objstm, 0, sizeof(*objstm));
|
||||
|
||||
- objstm->first = (uint32_t)objstm_first;
|
||||
- objstm->current = (uint32_t)objstm_first;
|
||||
+ objstm->first = (size_t)objstm_first;
|
||||
+ objstm->current = (size_t)objstm_first;
|
||||
objstm->current_pair = 0;
|
||||
- objstm->length = (uint32_t)objstm_length;
|
||||
- objstm->n = (uint32_t)objstm_n;
|
||||
+ objstm->length = (size_t)objstm_length;
|
||||
+ objstm->n = (size_t)objstm_n;
|
||||
|
||||
- cli_dbgmsg("pdf_extract_obj: ObjStm first obj at offset %d\n", objstm->first);
|
||||
- cli_dbgmsg("pdf_extract_obj: ObjStm length is %d bytes\n", objstm->length);
|
||||
- cli_dbgmsg("pdf_extract_obj: ObjStm should contain %d objects\n", objstm->n);
|
||||
+ cli_dbgmsg("pdf_extract_obj: ObjStm first obj at offset %zu\n", objstm->first);
|
||||
+ cli_dbgmsg("pdf_extract_obj: ObjStm length is %zu bytes\n", objstm->length);
|
||||
+ cli_dbgmsg("pdf_extract_obj: ObjStm should contain %zu objects\n", objstm->n);
|
||||
}
|
||||
}
|
||||
|
||||
- sum = pdf_decodestream(pdf, obj, dparams, obj->stream, (uint32_t)length, xref, fout, &rc, objstm);
|
||||
+ sum = pdf_decodestream(pdf, obj, dparams, obj->stream, length, xref, fout, &rc, objstm);
|
||||
if ((CL_SUCCESS != rc) && (CL_VIRUS != rc)) {
|
||||
cli_dbgmsg("Error decoding stream! Error code: %d\n", rc);
|
||||
|
||||
@@ -3341,7 +3341,7 @@ cl_error_t pdf_find_and_parse_objs_in_objstm(struct pdf_struct *pdf, struct objs
|
||||
retval = pdf_findobj_in_objstm(pdf, objstm, &obj);
|
||||
if (retval != CL_SUCCESS) {
|
||||
if (retval != CL_BREAK) {
|
||||
- cli_dbgmsg("pdf_find_and_parse_objs_in_objstm: Fewer objects in stream than expected: %u found, %u expected.\n",
|
||||
+ cli_dbgmsg("pdf_find_and_parse_objs_in_objstm: Fewer objects in stream than expected: %zu found, %zu expected.\n",
|
||||
objstm->nobjs_found, objstm->n);
|
||||
badobjects++;
|
||||
pdf->stats.ninvalidobjs++;
|
||||
diff --git a/libclamav/pdf.h b/libclamav/pdf.h
|
||||
index 3a03f19..b5b69ce 100644
|
||||
--- a/libclamav/pdf.h
|
||||
+++ b/libclamav/pdf.h
|
||||
@@ -25,14 +25,14 @@
|
||||
#define PDF_FILTERLIST_MAX 64
|
||||
|
||||
struct objstm_struct {
|
||||
- uint32_t first; // offset of first obj
|
||||
- uint32_t current; // offset of current obj
|
||||
- uint32_t current_pair; // offset of current pair describing id, location of object
|
||||
- uint32_t length; // total length of all objects (starting at first)
|
||||
- uint32_t n; // number of objects that should be found in the object stream
|
||||
- uint32_t nobjs_found; // number of objects actually found in the object stream
|
||||
- char *streambuf; // address of stream buffer, beginning with first obj pair
|
||||
- size_t streambuf_len; // length of stream buffer, includes pairs followed by actual objects
|
||||
+ size_t first; // offset of first obj
|
||||
+ size_t current; // offset of current obj
|
||||
+ size_t current_pair; // offset of current pair describing id, location of object
|
||||
+ size_t length; // total length of all objects (starting at first)
|
||||
+ size_t n; // number of objects that should be found in the object stream
|
||||
+ size_t nobjs_found; // number of objects actually found in the object stream
|
||||
+ char *streambuf; // address of stream buffer, beginning with first obj pair
|
||||
+ size_t streambuf_len; // length of stream buffer, includes pairs followed by actual objects
|
||||
};
|
||||
|
||||
struct pdf_obj {
|
||||
diff --git a/libclamav/pdfdecode.c b/libclamav/pdfdecode.c
|
||||
index 473cfcd..92ba52d 100644
|
||||
--- a/libclamav/pdfdecode.c
|
||||
+++ b/libclamav/pdfdecode.c
|
||||
@@ -73,7 +73,7 @@
|
||||
struct pdf_token {
|
||||
uint32_t flags; /* tracking flags */
|
||||
uint32_t success; /* successfully decoded filters */
|
||||
- uint32_t length; /* length of current content; TODO: transition to size_t */
|
||||
+ size_t length; /* length of current content; TODO: transition to size_t */
|
||||
uint8_t *content; /* content stream */
|
||||
};
|
||||
|
||||
@@ -461,10 +461,16 @@ static cl_error_t filter_ascii85decode(struct pdf_struct *pdf, struct pdf_obj *o
|
||||
uint32_t declen = 0;
|
||||
|
||||
const uint8_t *ptr = (uint8_t *)token->content;
|
||||
- uint32_t remaining = token->length;
|
||||
+ size_t remaining = token->length;
|
||||
int quintet = 0, rc = CL_SUCCESS;
|
||||
uint64_t sum = 0;
|
||||
|
||||
+ /* Check for overflow */
|
||||
+ if (remaining > (SIZE_MAX / 4)) {
|
||||
+ cli_dbgmsg("cli_pdf: ascii85decode: overflow detected\n");
|
||||
+ return CL_EFORMAT;
|
||||
+ }
|
||||
+
|
||||
/* 5:4 decoding ratio, with 1:4 expansion sequences => (4*length)+1 */
|
||||
if (!(dptr = decoded = (uint8_t *)cli_malloc((4 * remaining) + 1))) {
|
||||
cli_errmsg("cli_pdf: cannot allocate memory for decoded output\n");
|
||||
@@ -851,8 +857,8 @@ static cl_error_t filter_asciihexdecode(struct pdf_struct *pdf, struct pdf_obj *
|
||||
uint8_t *decoded;
|
||||
|
||||
const uint8_t *content = (uint8_t *)token->content;
|
||||
- uint32_t length = token->length;
|
||||
- uint32_t i, j;
|
||||
+ size_t length = token->length;
|
||||
+ size_t i, j;
|
||||
cl_error_t rc = CL_SUCCESS;
|
||||
|
||||
if (!(decoded = (uint8_t *)cli_calloc(length / 2 + 1, sizeof(uint8_t)))) {
|
||||
@@ -882,8 +888,8 @@ static cl_error_t filter_asciihexdecode(struct pdf_struct *pdf, struct pdf_obj *
|
||||
if (rc == CL_SUCCESS) {
|
||||
free(token->content);
|
||||
|
||||
- cli_dbgmsg("cli_pdf: deflated %lu bytes from %lu total bytes\n",
|
||||
- (unsigned long)j, (unsigned long)(token->length));
|
||||
+ cli_dbgmsg("cli_pdf: deflated %zu bytes from %zu total bytes\n",
|
||||
+ j, token->length);
|
||||
|
||||
token->content = decoded;
|
||||
token->length = j;
|
||||
@@ -891,8 +897,8 @@ static cl_error_t filter_asciihexdecode(struct pdf_struct *pdf, struct pdf_obj *
|
||||
if (!(obj->flags & ((1 << OBJ_IMAGE) | (1 << OBJ_TRUNCATED))))
|
||||
pdfobj_flag(pdf, obj, BAD_ASCIIDECODE);
|
||||
|
||||
- cli_dbgmsg("cli_pdf: error occurred parsing byte %lu of %lu\n",
|
||||
- (unsigned long)i, (unsigned long)(token->length));
|
||||
+ cli_dbgmsg("cli_pdf: error occurred parsing byte %zu of %zu\n",
|
||||
+ i, token->length);
|
||||
free(decoded);
|
||||
}
|
||||
return rc;
|
||||
@@ -933,27 +939,29 @@ static cl_error_t filter_decrypt(struct pdf_struct *pdf, struct pdf_obj *obj, st
|
||||
return CL_EPARSE; /* TODO: what should this value be? CL_SUCCESS would mirror previous behavior */
|
||||
}
|
||||
|
||||
- cli_dbgmsg("cli_pdf: decrypted %zu bytes from %u total bytes\n",
|
||||
+ cli_dbgmsg("cli_pdf: decrypted %zu bytes from %zu total bytes\n",
|
||||
length, token->length);
|
||||
|
||||
free(token->content);
|
||||
token->content = (uint8_t *)decrypted;
|
||||
- token->length = (uint32_t)length; /* this may truncate unfortunately, TODO: use 64-bit values internally? */
|
||||
+ token->length = length;
|
||||
return CL_SUCCESS;
|
||||
}
|
||||
|
||||
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;
|
||||
- uint32_t declen = 0, capacity = 0;
|
||||
+ size_t declen = 0, capacity = 0;
|
||||
|
||||
uint8_t *content = (uint8_t *)token->content;
|
||||
uint32_t length = token->length;
|
||||
lzw_stream stream;
|
||||
int echg = 1, lzwstat, rc = CL_SUCCESS;
|
||||
|
||||
- if (pdf->ctx && !(pdf->ctx->dconf->other & OTHER_CONF_LZW))
|
||||
- return CL_BREAK;
|
||||
+ if (pdf->ctx && !(pdf->ctx->dconf->other & OTHER_CONF_LZW)) {
|
||||
+ rc = CL_BREAK;
|
||||
+ goto done;
|
||||
+ }
|
||||
|
||||
if (params) {
|
||||
struct pdf_dict_node *node = params->nodes;
|
||||
@@ -984,15 +992,18 @@ static cl_error_t filter_lzwdecode(struct pdf_struct *pdf, struct pdf_obj *obj,
|
||||
* Sample 0015315109, it has \r followed by zlib header.
|
||||
* Flag pdf as suspicious, and attempt to extract by skipping the \r.
|
||||
*/
|
||||
- if (!length)
|
||||
- return CL_SUCCESS;
|
||||
+ if (!length) {
|
||||
+ rc = CL_SUCCESS;
|
||||
+ goto done;
|
||||
+ }
|
||||
}
|
||||
|
||||
capacity = INFLATE_CHUNK_SIZE;
|
||||
|
||||
if (!(decoded = (uint8_t *)cli_malloc(capacity))) {
|
||||
cli_errmsg("cli_pdf: cannot allocate memory for decoded output\n");
|
||||
- return CL_EMEM;
|
||||
+ rc = CL_EMEM;
|
||||
+ goto done;
|
||||
}
|
||||
|
||||
memset(&stream, 0, sizeof(stream));
|
||||
@@ -1007,7 +1018,8 @@ static cl_error_t filter_lzwdecode(struct pdf_struct *pdf, struct pdf_obj *obj,
|
||||
if (lzwstat != Z_OK) {
|
||||
cli_warnmsg("cli_pdf: lzwInit failed\n");
|
||||
free(decoded);
|
||||
- return CL_EMEM;
|
||||
+ rc = CL_EMEM;
|
||||
+ goto done;
|
||||
}
|
||||
|
||||
/* initial inflate */
|
||||
@@ -1022,16 +1034,23 @@ static cl_error_t filter_lzwdecode(struct pdf_struct *pdf, struct pdf_obj *obj,
|
||||
length -= q - content;
|
||||
content = q;
|
||||
|
||||
- stream.next_in = (Bytef *)content;
|
||||
- stream.avail_in = length;
|
||||
- stream.next_out = (Bytef *)decoded;
|
||||
+ stream.next_in = (Bytef *)content;
|
||||
+ stream.avail_in = length;
|
||||
+ stream.next_out = (Bytef *)decoded;
|
||||
+ /* Make sure we don't overflow during type conversion */
|
||||
+ if (capacity > UINT_MAX) {
|
||||
+ cli_dbgmsg("cli_pdf: lzwdecode: overflow detected\n");
|
||||
+ rc = CL_EFORMAT;
|
||||
+ goto done;
|
||||
+ }
|
||||
stream.avail_out = capacity;
|
||||
|
||||
lzwstat = lzwInit(&stream);
|
||||
if (lzwstat != Z_OK) {
|
||||
cli_warnmsg("cli_pdf: lzwInit failed\n");
|
||||
free(decoded);
|
||||
- return CL_EMEM;
|
||||
+ rc = CL_EMEM;
|
||||
+ goto done;
|
||||
}
|
||||
|
||||
pdfobj_flag(pdf, obj, BAD_FLATESTART);
|
||||
@@ -1044,7 +1063,7 @@ static cl_error_t filter_lzwdecode(struct pdf_struct *pdf, struct pdf_obj *obj,
|
||||
/* extend output capacity if needed,*/
|
||||
if (stream.avail_out == 0) {
|
||||
if ((rc = cli_checklimits("pdf", pdf->ctx, capacity + INFLATE_CHUNK_SIZE, 0, 0)) != CL_SUCCESS) {
|
||||
- cli_dbgmsg("cli_pdf: required buffer size to inflate compressed filter exceeds maximum: %u\n", capacity + INFLATE_CHUNK_SIZE);
|
||||
+ cli_dbgmsg("cli_pdf: required buffer size to inflate compressed filter exceeds maximum: %zu\n", capacity + INFLATE_CHUNK_SIZE);
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1056,7 +1075,17 @@ static cl_error_t filter_lzwdecode(struct pdf_struct *pdf, struct pdf_obj *obj,
|
||||
decoded = temp;
|
||||
stream.next_out = decoded + capacity;
|
||||
stream.avail_out = INFLATE_CHUNK_SIZE;
|
||||
+ if (declen > (SIZE_MAX - INFLATE_CHUNK_SIZE)) {
|
||||
+ cli_dbgmsg("cli_pdf: lzwdecode: overflow detected\n");
|
||||
+ rc = CL_EFORMAT;
|
||||
+ goto done;
|
||||
+ }
|
||||
declen += INFLATE_CHUNK_SIZE;
|
||||
+ if (capacity > (SIZE_MAX - INFLATE_CHUNK_SIZE)) {
|
||||
+ cli_dbgmsg("cli_pdf: lzwdecode: overflow detected\n");
|
||||
+ rc = CL_EFORMAT;
|
||||
+ goto done;
|
||||
+ }
|
||||
capacity += INFLATE_CHUNK_SIZE;
|
||||
}
|
||||
|
||||
@@ -1064,6 +1093,12 @@ static cl_error_t filter_lzwdecode(struct pdf_struct *pdf, struct pdf_obj *obj,
|
||||
lzwstat = lzwInflate(&stream);
|
||||
}
|
||||
|
||||
+ if (declen > (UINT32_MAX - (INFLATE_CHUNK_SIZE - stream.avail_out))) {
|
||||
+ cli_dbgmsg("cli_pdf: lzwdecode: overflow detected\n");
|
||||
+ rc = CL_EFORMAT;
|
||||
+ goto done;
|
||||
+ }
|
||||
+
|
||||
/* add stream end fragment to decoded length */
|
||||
declen += (INFLATE_CHUNK_SIZE - stream.avail_out);
|
||||
|
||||
@@ -1104,6 +1139,7 @@ static cl_error_t filter_lzwdecode(struct pdf_struct *pdf, struct pdf_obj *obj,
|
||||
|
||||
(void)lzwInflateEnd(&stream);
|
||||
|
||||
+done:
|
||||
if (rc == CL_SUCCESS) {
|
||||
if (declen == 0) {
|
||||
cli_dbgmsg("cli_pdf: empty stream after inflation completed.\n");
|
||||
@@ -0,0 +1,34 @@
|
||||
From fd9cf81463725023d25838a08c8de459f619a58c Mon Sep 17 00:00:00 2001
|
||||
From: Val Snyder <micasnyd@cisco.com>
|
||||
Date: Wed, 12 Mar 2025 16:08:25 -0400
|
||||
Subject: [PATCH] Fix lzma-sdk xz bug
|
||||
|
||||
A use-after-free read is possible in the Xz decoder cleanup.
|
||||
|
||||
The fix is to set a pointer to NULL so it doesn't try to
|
||||
dereference it and free a second time.
|
||||
|
||||
Fixes https://issues.oss-fuzz.com/issues/384549094
|
||||
|
||||
This fix is also present in lzma-sdk version 18.01.
|
||||
Ref: https://github.com/welovegit/LZMA-SDK/blame/main/C/XzDec.c#L508
|
||||
---
|
||||
libclamav/7z/XzDec.c | 4 +++-
|
||||
1 file changed, 3 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/libclamav/7z/XzDec.c b/libclamav/7z/XzDec.c
|
||||
index 00a28702f5..7e40d202fb 100644
|
||||
--- a/libclamav/7z/XzDec.c
|
||||
+++ b/libclamav/7z/XzDec.c
|
||||
@@ -343,8 +343,10 @@ void MixCoder_Free(CMixCoder *p)
|
||||
for (i = 0; i < p->numCoders; i++)
|
||||
{
|
||||
IStateCoder *sc = &p->coders[i];
|
||||
- if (p->alloc && sc->p)
|
||||
+ if (p->alloc && sc->p) {
|
||||
sc->Free(sc->p, p->alloc);
|
||||
+ sc->p = NULL;
|
||||
+ }
|
||||
}
|
||||
p->numCoders = 0;
|
||||
if (p->buf)
|
||||
Reference in New Issue
Block a user