Skip to content

Commit 0542087

Browse files
authored
Merge pull request #8 from cisco-sbg/CLAM-2638-CLAM-2627-CLAM-2634-1.4.1-changes-with-CVE-fixes
Clam 2638 clam 2627 clam 2634 1.4.1 changes with CVE fixes
2 parents cad552d + d898fb4 commit 0542087

File tree

9 files changed

+124
-25
lines changed

9 files changed

+124
-25
lines changed

CMakeLists.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ string(TIMESTAMP TODAY "%Y%m%d")
2222
set(VERSION_SUFFIX "")
2323

2424
project( ClamAV
25-
VERSION "1.4.0"
25+
VERSION "1.4.1"
2626
DESCRIPTION "ClamAV open source email, web, and end-point anti-virus toolkit." )
2727

2828
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH})

Jenkinsfile

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ properties(
1010
parameters(
1111
[
1212
string(name: 'VERSION',
13-
defaultValue: '1.4.0',
13+
defaultValue: '1.4.1',
1414
description: 'ClamAV version string'),
1515
string(name: 'FRAMEWORK_BRANCH',
1616
defaultValue: '1.4',

NEWS.md

+32
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,38 @@
33
Note: This file refers to the official packages. Things described here may
44
differ slightly from third-party binary packages.
55

6+
## 1.4.1
7+
8+
ClamAV 1.4.1 is a critical patch release with the following fixes:
9+
10+
- [CVE-2024-20506](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-20506):
11+
Changed the logging module to disable following symlinks on Linux and Unix
12+
systems so as to prevent an attacker with existing access to the 'clamd' or
13+
'freshclam' services from using a symlink to corrupt system files.
14+
15+
This issue affects all currently supported versions. It will be fixed in:
16+
- 1.4.1
17+
- 1.3.2
18+
- 1.0.7
19+
- 0.103.12
20+
21+
Thank you to Detlef for identifying this issue.
22+
23+
- [CVE-2024-20505](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-20505):
24+
Fixed a possible out-of-bounds read bug in the PDF file parser that could
25+
cause a denial-of-service (DoS) condition.
26+
27+
This issue affects all currently supported versions. It will be fixed in:
28+
- 1.4.1
29+
- 1.3.2
30+
- 1.0.7
31+
- 0.103.12
32+
33+
Thank you to OSS-Fuzz for identifying this issue.
34+
35+
- Removed unused Python modules from freshclam tests including deprecated
36+
'cgi' module that is expected to cause test failures in Python 3.13.
37+
638
## 1.4.0
739

840
ClamAV 1.4.0 includes the following improvements and changes:

common/output.c

+40-11
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,12 @@
5858

5959
#include "output.h"
6060

61+
// Define O_NOFOLLOW for systems that don't have it.
62+
// Notably, Windows doesn't have O_NOFOLLOW.
63+
#ifndef O_NOFOLLOW
64+
#define O_NOFOLLOW 0
65+
#endif
66+
6167
#ifdef CL_THREAD_SAFE
6268
#include <pthread.h>
6369
pthread_mutex_t logg_mutex = PTHREAD_MUTEX_INITIALIZER;
@@ -304,7 +310,6 @@ int logg(loglevel_t loglevel, const char *str, ...)
304310
char buffer[1025], *abuffer = NULL, *buff;
305311
time_t currtime;
306312
size_t len;
307-
mode_t old_umask;
308313
#ifdef F_WRLCK
309314
struct flock fl;
310315
#endif
@@ -338,18 +343,36 @@ int logg(loglevel_t loglevel, const char *str, ...)
338343
logg_open();
339344

340345
if (!logg_fp && logg_file) {
341-
old_umask = umask(0037);
342-
if ((logg_fp = fopen(logg_file, "at")) == NULL) {
343-
umask(old_umask);
346+
int logg_file_fd = -1;
347+
348+
logg_file_fd = open(logg_file, O_WRONLY | O_CREAT | O_APPEND | O_NOFOLLOW, 0640);
349+
if (-1 == logg_file_fd) {
350+
char errbuf[128];
351+
cli_strerror(errno, errbuf, sizeof(errbuf));
352+
printf("ERROR: Failed to open log file %s: %s\n", logg_file, errbuf);
353+
344354
#ifdef CL_THREAD_SAFE
345355
pthread_mutex_unlock(&logg_mutex);
346356
#endif
347-
printf("ERROR: Can't open %s in append mode (check permissions!).\n", logg_file);
348-
if (len > sizeof(buffer))
357+
if (abuffer)
349358
free(abuffer);
350359
return -1;
351-
} else
352-
umask(old_umask);
360+
}
361+
362+
logg_fp = fdopen(logg_file_fd, "at");
363+
if (NULL == logg_fp) {
364+
char errbuf[128];
365+
cli_strerror(errno, errbuf, sizeof(errbuf));
366+
printf("ERROR: Failed to convert the open log file descriptor for %s to a FILE* handle: %s\n", logg_file, errbuf);
367+
368+
close(logg_file_fd);
369+
#ifdef CL_THREAD_SAFE
370+
pthread_mutex_unlock(&logg_mutex);
371+
#endif
372+
if (abuffer)
373+
free(abuffer);
374+
return -1;
375+
}
353376

354377
#ifdef F_WRLCK
355378
if (logg_lock) {
@@ -362,11 +385,16 @@ int logg(loglevel_t loglevel, const char *str, ...)
362385
else
363386
#endif
364387
{
388+
char errbuf[128];
389+
cli_strerror(errno, errbuf, sizeof(errbuf));
390+
printf("ERROR: Failed to lock the log file %s: %s\n", logg_file, errbuf);
391+
365392
#ifdef CL_THREAD_SAFE
366393
pthread_mutex_unlock(&logg_mutex);
367394
#endif
368-
printf("ERROR: %s is locked by another process\n", logg_file);
369-
if (len > sizeof(buffer))
395+
fclose(logg_fp);
396+
logg_fp = NULL;
397+
if (abuffer)
370398
free(abuffer);
371399
return -1;
372400
}
@@ -441,8 +469,9 @@ int logg(loglevel_t loglevel, const char *str, ...)
441469
pthread_mutex_unlock(&logg_mutex);
442470
#endif
443471

444-
if (len > sizeof(buffer))
472+
if (abuffer)
445473
free(abuffer);
474+
446475
return 0;
447476
}
448477

libclamav/bytecode_api.h

+5-1
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,7 @@ enum FunctionalityLevels {
157157
FUNC_LEVEL_0103_9 = 130, /**< LibClamAV release 0.103.9 */
158158
FUNC_LEVEL_0103_10 = 131, /**< LibClamAV release 0.103.10 */
159159
FUNC_LEVEL_0103_11 = 132, /**< LibClamAV release 0.103.11 */
160+
FUNC_LEVEL_0103_12 = 133, /**< LibClamAV release 0.103.12 */
160161

161162
FUNC_LEVEL_0104 = 140, /**< LibClamAV release 0.104.0 */
162163
FUNC_LEVEL_0104_1 = 141, /**< LibClamAV release 0.104.1 */
@@ -175,6 +176,7 @@ enum FunctionalityLevels {
175176
FUNC_LEVEL_1_0_4 = 164, /**< LibClamAV release 1.0.4 */
176177
FUNC_LEVEL_1_0_5 = 165, /**< LibClamAV release 1.0.5 */
177178
FUNC_LEVEL_1_0_6 = 166, /**< LibClamAV release 1.0.6 */
179+
FUNC_LEVEL_1_0_7 = 167, /**< LibClamAV release 1.0.7 */
178180

179181
FUNC_LEVEL_1_1 = 180, /**< LibClamAV release 1.1.0 */
180182
FUNC_LEVEL_1_1_1 = 181, /**< LibClamAV release 1.1.1 */
@@ -188,8 +190,10 @@ enum FunctionalityLevels {
188190

189191
FUNC_LEVEL_1_3 = 200, /**< LibClamAV release 1.3.0 */
190192
FUNC_LEVEL_1_3_1 = 201, /**< LibClamAV release 1.3.1 */
193+
FUNC_LEVEL_1_3_2 = 202, /**< LibClamAV release 1.3.2 */
191194

192-
FUNC_LEVEL_1_4 = 210, /**< LibClamAV release 1.4.0 */
195+
FUNC_LEVEL_1_4 = 210, /**< LibClamAV release 1.4.0 */
196+
FUNC_LEVEL_1_4_1 = 211, /**< LibClamAV release 1.4.1 */
193197
};
194198

195199
/**

libclamav/others.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@
6969
* in re-enabling affected modules.
7070
*/
7171

72-
#define CL_FLEVEL 210
72+
#define CL_FLEVEL 211
7373
#define CL_FLEVEL_DCONF CL_FLEVEL
7474
#define CL_FLEVEL_SIGTOOL CL_FLEVEL
7575

libclamav/pdf.c

+39-6
Original file line numberDiff line numberDiff line change
@@ -1003,8 +1003,26 @@ static size_t find_length(struct pdf_struct *pdf, struct pdf_obj *obj, const cha
10031003
return 0;
10041004
}
10051005

1006-
indirect_obj_start = pdf->map + obj->start;
1007-
bytes_remaining = pdf->size - obj->start;
1006+
if (NULL == obj->objstm) {
1007+
indirect_obj_start = (const char *)(obj->start + pdf->map);
1008+
1009+
if (!CLI_ISCONTAINED(pdf->map, pdf->size, indirect_obj_start, obj->size)) {
1010+
cli_dbgmsg("find_length: indirect object found, but not contained in PDF\n");
1011+
return 0;
1012+
}
1013+
1014+
bytes_remaining = pdf->size - obj->start;
1015+
1016+
} else {
1017+
indirect_obj_start = (const char *)(obj->start + obj->objstm->streambuf);
1018+
1019+
if (!CLI_ISCONTAINED(obj->objstm->streambuf, obj->objstm->streambuf_len, indirect_obj_start, obj->size)) {
1020+
cli_dbgmsg("find_length: indirect object found, but not contained in PDF streambuf\n");
1021+
return 0;
1022+
}
1023+
1024+
bytes_remaining = obj->objstm->streambuf_len - obj->start;
1025+
}
10081026

10091027
/* Ok so we found the indirect object, lets read the value. */
10101028
index = pdf_nextobject(indirect_obj_start, bytes_remaining);
@@ -3260,15 +3278,30 @@ void pdf_handle_enc(struct pdf_struct *pdf)
32603278

32613279
obj = find_obj(pdf, pdf->objs[0], pdf->enc_objid);
32623280
if (!obj) {
3263-
cli_dbgmsg("pdf_handle_enc: can't find encrypted object %d %d\n", pdf->enc_objid >> 8, pdf->enc_objid & 0xff);
3264-
noisy_warnmsg("pdf_handle_enc: can't find encrypted object %d %d\n", pdf->enc_objid >> 8, pdf->enc_objid & 0xff);
3281+
cli_dbgmsg("pdf_handle_enc: can't find encryption object %d %d\n", pdf->enc_objid >> 8, pdf->enc_objid & 0xff);
3282+
noisy_warnmsg("pdf_handle_enc: can't find encryption object %d %d\n", pdf->enc_objid >> 8, pdf->enc_objid & 0xff);
32653283
return;
32663284
}
32673285

32683286
len = obj->size;
32693287

3270-
q = (obj->objstm) ? (const char *)(obj->start + obj->objstm->streambuf)
3271-
: (const char *)(obj->start + pdf->map);
3288+
if (NULL == obj->objstm) {
3289+
q = (const char *)(obj->start + pdf->map);
3290+
3291+
if (!CLI_ISCONTAINED(pdf->map, pdf->size, q, len)) {
3292+
cli_dbgmsg("pdf_handle_enc: encryption object found, but not contained in PDF\n");
3293+
noisy_warnmsg("pdf_handle_enc: encryption object found, but not contained in PDF\n");
3294+
return;
3295+
}
3296+
} else {
3297+
q = (const char *)(obj->start + obj->objstm->streambuf);
3298+
3299+
if (!CLI_ISCONTAINED(obj->objstm->streambuf, obj->objstm->streambuf_len, q, len)) {
3300+
cli_dbgmsg("pdf_handle_enc: encryption object found, but not contained in PDF streambuf\n");
3301+
noisy_warnmsg("pdf_handle_enc: encryption object found, but not contained in PDF streambuf\n");
3302+
return;
3303+
}
3304+
}
32723305

32733306
O = U = UE = StmF = StrF = EFF = NULL;
32743307

libclamav/pdfng.c

+5
Original file line numberDiff line numberDiff line change
@@ -518,6 +518,11 @@ char *pdf_parse_string(struct pdf_struct *pdf, struct pdf_obj *obj, const char *
518518
if (!(newobj))
519519
return NULL;
520520

521+
if (!CLI_ISCONTAINED(pdf->map, pdf->size, newobj->start, newobj->size)) {
522+
cli_dbgmsg("pdf_parse_string: object not contained in PDF\n");
523+
return NULL;
524+
}
525+
521526
if (newobj == obj)
522527
return NULL;
523528

unit_tests/freshclam_test.py

-4
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,10 @@
1010
from pathlib import Path
1111
import platform
1212
import shutil
13-
import subprocess
14-
import sys
15-
import time
1613
import unittest
1714
from functools import partial
1815

1916
from http.server import HTTPServer, BaseHTTPRequestHandler
20-
import cgi
2117

2218
import testcase
2319

0 commit comments

Comments
 (0)