Skip to content

Commit 2962509

Browse files
matthias-fratz-bszval-ms
authored andcommitted
Raise artificial 4G limit for MaxScanSize
This limit is internally "long long", so >=64-bit even on 32-bit platforms. Also fixes a related issue where limits could have been set to negative values on 64-bit platforms where setting a "long long" (64-bit signed) can overflow if assigned from an "unsigned long" (64-bit unsigned). Resolves: #809
1 parent e4ac4b6 commit 2962509

2 files changed

Lines changed: 48 additions & 17 deletions

File tree

common/optparser.c

Lines changed: 46 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@
6363
#define MAXCMDOPTS 150
6464

6565
#define MATCH_NUMBER "^[0-9]+$"
66-
#define MATCH_SIZE "^[0-9]+[KM]?$"
66+
#define MATCH_SIZE "^[0-9]+[KMG]?$"
6767
#define MATCH_BOOL "^(yes|true|1|no|false|0)$"
6868

6969
#define FLAG_MULTIPLE 1 /* option can be used multiple times */
@@ -440,7 +440,7 @@ const struct clam_option __clam_options[] = {
440440

441441
{"MaxScanTime", "max-scantime", 0, CLOPT_TYPE_NUMBER, MATCH_NUMBER, 0, NULL, 0, OPT_CLAMD | OPT_CLAMSCAN, "This option sets the maximum amount of time a scan may take to complete.\nThe value of 0 disables the limit.\nWARNING: disabling this limit or setting it too high may result allow scanning\nof certain files to lock up the scanning process/threads resulting in a Denial of Service.\nThe value is in milliseconds.", "120000"},
442442

443-
{"MaxScanSize", "max-scansize", 0, CLOPT_TYPE_SIZE, MATCH_SIZE, CLI_DEFAULT_MAXSCANSIZE, NULL, 0, OPT_CLAMD | OPT_CLAMSCAN, "This option sets the maximum amount of data to be scanned for each input file.\nArchives and other containers are recursively extracted and scanned up to this\nvalue.\nThe value of 0 disables the limit.\nWARNING: disabling this limit or setting it too high may result in severe\ndamage.", "400M"},
443+
{"MaxScanSize", "max-scansize", 0, CLOPT_TYPE_SIZE64, MATCH_SIZE, CLI_DEFAULT_MAXSCANSIZE, NULL, 0, OPT_CLAMD | OPT_CLAMSCAN, "This option sets the maximum amount of data to be scanned for each input file.\nArchives and other containers are recursively extracted and scanned up to this\nvalue.\nThe value of 0 disables the limit.\nWARNING: disabling this limit or setting it too high may result in severe\ndamage.", "400M"},
444444

445445
{"MaxFileSize", "max-filesize", 0, CLOPT_TYPE_SIZE, MATCH_SIZE, CLI_DEFAULT_MAXFILESIZE, NULL, 0, OPT_CLAMD | OPT_MILTER | OPT_CLAMSCAN, "Files/messages larger than this limit won't be scanned. Affects the input\nfile itself as well as files contained inside it (when the input file is\nan archive, a document or some other kind of container).\nThe value of 0 disables the limit.\nWARNING: disabling this limit or setting it too high may result in severe\ndamage to the system.", "100M"},
446446

@@ -646,7 +646,7 @@ const struct clam_option __clam_options[] = {
646646
{"LeaveTemporaryFiles", NULL, 0, CLOPT_TYPE_BOOL, MATCH_BOOL, -1, NULL, 0, OPT_MILTER | OPT_DEPRECATED, "", ""},
647647
{"LocalSocket", NULL, 0, CLOPT_TYPE_STRING, NULL, -1, NULL, 0, OPT_MILTER | OPT_DEPRECATED, "", ""},
648648
{"MailFollowURLs", NULL, 0, CLOPT_TYPE_BOOL, MATCH_BOOL, -1, NULL, 0, OPT_MILTER | OPT_DEPRECATED, "", ""},
649-
{"MaxScanSize", NULL, 0, CLOPT_TYPE_SIZE, MATCH_SIZE, -1, NULL, 0, OPT_MILTER | OPT_DEPRECATED, "", ""},
649+
{"MaxScanSize", NULL, 0, CLOPT_TYPE_SIZE64, MATCH_SIZE, -1, NULL, 0, OPT_MILTER | OPT_DEPRECATED, "", ""},
650650
{"MaxFiles", NULL, 0, CLOPT_TYPE_NUMBER, MATCH_NUMBER, -1, NULL, 0, OPT_MILTER | OPT_DEPRECATED, "", ""},
651651
{"MaxRecursion", NULL, 0, CLOPT_TYPE_NUMBER, MATCH_NUMBER, -1, NULL, 0, OPT_MILTER | OPT_DEPRECATED, "", ""},
652652
{"PhishingSignatures", NULL, 0, CLOPT_TYPE_BOOL, MATCH_BOOL, -1, NULL, 0, OPT_MILTER | OPT_DEPRECATED, "", ""},
@@ -923,7 +923,7 @@ struct optstruct *optparse(const char *cfgfile, int argc, char **argv, int verbo
923923
struct option longopts[MAXCMDOPTS];
924924
char shortopts[MAXCMDOPTS];
925925
regex_t regex;
926-
long long numarg, lnumarg;
926+
long long numarg, lnumarg, lnumlimit;
927927
int regflags = REG_EXTENDED | REG_NOSUB;
928928

929929
#ifdef _WIN32
@@ -1204,25 +1204,40 @@ struct optstruct *optparse(const char *cfgfile, int argc, char **argv, int verbo
12041204
break;
12051205

12061206
case CLOPT_TYPE_SIZE:
1207+
case CLOPT_TYPE_SIZE64:
1208+
if (optentry->argtype == CLOPT_TYPE_SIZE64)
1209+
/* guaranteed to be "long long" (64 bit but possibly signed) further down the line */
1210+
lnumlimit = LLONG_MAX;
1211+
else
1212+
/* probably mostly "unsigned long int" (32 or 64 bit unsigned depending on platform),
1213+
* but may be expected to fit into a "long long" (64-bit signed) */
1214+
lnumlimit = LLONG_MAX < ULONG_MAX ? LLONG_MAX : ULONG_MAX;
12071215
errno = 0;
12081216
if (arg)
1209-
lnumarg = strtoul(arg, &buff, 0);
1217+
lnumarg = strtoll(arg, &buff, 0);
12101218
else {
12111219
numarg = 0;
12121220
break;
12131221
}
12141222
if (errno != ERANGE) {
12151223
switch (*buff) {
1224+
case 'G':
1225+
case 'g':
1226+
if (lnumarg <= lnumlimit / (1024 * 1024 * 1024))
1227+
lnumarg *= 1024 * 1024 * 1024;
1228+
else
1229+
errno = ERANGE;
1230+
break;
12161231
case 'M':
12171232
case 'm':
1218-
if (lnumarg <= UINT_MAX / (1024 * 1024))
1233+
if (lnumarg <= lnumlimit / (1024 * 1024))
12191234
lnumarg *= 1024 * 1024;
12201235
else
12211236
errno = ERANGE;
12221237
break;
12231238
case 'K':
12241239
case 'k':
1225-
if (lnumarg <= UINT_MAX / 1024)
1240+
if (lnumarg <= lnumlimit / 1024)
12261241
lnumarg *= 1024;
12271242
else
12281243
errno = ERANGE;
@@ -1246,17 +1261,17 @@ struct optstruct *optparse(const char *cfgfile, int argc, char **argv, int verbo
12461261
if (err) break;
12471262
if (errno == ERANGE) {
12481263
if (cfgfile) {
1249-
fprintf(stderr, "WARNING: Numerical value for option %s too high, resetting to 4G\n", name);
1264+
fprintf(stderr, "WARNING: Numerical value for option %s too high, resetting to %lld\n", name, lnumlimit);
12501265
} else {
12511266
if (optentry->shortopt)
1252-
fprintf(stderr, "WARNING: Numerical value for option --%s (-%c) too high, resetting to 4G\n", optentry->longopt, optentry->shortopt);
1267+
fprintf(stderr, "WARNING: Numerical value for option --%s (-%c) too high, resetting to %lld\n", optentry->longopt, optentry->shortopt, lnumlimit);
12531268
else
1254-
fprintf(stderr, "WARNING: Numerical value for option %s too high, resetting to 4G\n", optentry->longopt);
1269+
fprintf(stderr, "WARNING: Numerical value for option %s too high, resetting to %lld\n", optentry->longopt, lnumlimit);
12551270
}
1256-
lnumarg = UINT_MAX;
1271+
lnumarg = lnumlimit;
12571272
}
12581273

1259-
numarg = lnumarg ? lnumarg : UINT_MAX;
1274+
numarg = lnumarg ? lnumarg : lnumlimit;
12601275
break;
12611276

12621277
case CLOPT_TYPE_BOOL:
@@ -1319,7 +1334,7 @@ struct optstruct *optadditem(const char *name, const char *arg, int verbose, int
13191334
struct optstruct *opts = NULL, *opts_last = NULL, *opt;
13201335
char *buff;
13211336
regex_t regex;
1322-
long long numarg, lnumarg;
1337+
long long numarg, lnumarg, lnumlimit;
13231338
int regflags = REG_EXTENDED | REG_NOSUB;
13241339
const struct clam_option *optentry = NULL;
13251340

@@ -1417,25 +1432,40 @@ struct optstruct *optadditem(const char *name, const char *arg, int verbose, int
14171432
break;
14181433

14191434
case CLOPT_TYPE_SIZE:
1435+
case CLOPT_TYPE_SIZE64:
1436+
if (optentry->argtype == CLOPT_TYPE_SIZE64)
1437+
/* guaranteed to be "long long" (64 bit but possibly signed) further down the line */
1438+
lnumlimit = LLONG_MAX;
1439+
else
1440+
/* probably mostly "unsigned long int" (32 or 64 bit unsigned depending on platform),
1441+
* but may be expected to fit into a "long long" (64-bit signed) */
1442+
lnumlimit = LLONG_MAX < ULONG_MAX ? LLONG_MAX : ULONG_MAX;
14201443
errno = 0;
14211444
if (arg)
1422-
lnumarg = strtoul(arg, &buff, 0);
1445+
lnumarg = strtoll(arg, &buff, 0);
14231446
else {
14241447
numarg = 0;
14251448
break;
14261449
}
14271450
if (errno != ERANGE) {
14281451
switch (*buff) {
1452+
case 'G':
1453+
case 'g':
1454+
if (lnumarg <= lnumlimit / (1024 * 1024 * 1024))
1455+
lnumarg *= 1024 * 1024 * 1024;
1456+
else
1457+
errno = ERANGE;
1458+
break;
14291459
case 'M':
14301460
case 'm':
1431-
if (lnumarg <= UINT_MAX / (1024 * 1024))
1461+
if (lnumarg <= lnumlimit / (1024 * 1024))
14321462
lnumarg *= 1024 * 1024;
14331463
else
14341464
errno = ERANGE;
14351465
break;
14361466
case 'K':
14371467
case 'k':
1438-
if (lnumarg <= UINT_MAX / 1024)
1468+
if (lnumarg <= lnumlimit / 1024)
14391469
lnumarg *= 1024;
14401470
else
14411471
errno = ERANGE;

common/optparser.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,9 @@
3838

3939
#define CLOPT_TYPE_STRING 1 /* quoted/regular string */
4040
#define CLOPT_TYPE_NUMBER 2 /* raw number */
41-
#define CLOPT_TYPE_SIZE 3 /* number possibly followed by modifiers (M/m or K/k) */
41+
#define CLOPT_TYPE_SIZE 3 /* number possibly followed by modifiers (K/k, M/m or G/g) */
4242
#define CLOPT_TYPE_BOOL 4 /* boolean */
43+
#define CLOPT_TYPE_SIZE64 5 /* 64-bit number possibly followed by modifiers (K/k, M/m or G/g) */
4344

4445
#ifdef _WIN32
4546
extern char _DATADIR[MAX_PATH];

0 commit comments

Comments
 (0)