... | ... |
@@ -1,3 +1,7 @@ |
1 |
+Fri Nov 8 17:08:09 2013 EDT 2013 (morgan) |
|
2 |
+------------------------------------ |
|
3 |
+ * Add ForceToDisk option for clamd and force-to-disk arg for clamscan |
|
4 |
+ |
|
1 | 5 |
Wed Oct 31 12:48:00 2013 EDT 2013 (morgan) |
2 | 6 |
------------------------------------ |
3 | 7 |
* libclamav: bb#5341 - Change floating point byte order check from compile time to run time. |
... | ... |
@@ -431,6 +431,9 @@ int main(int argc, char **argv) |
431 | 431 |
if(optget(opts, "LeaveTemporaryFiles")->enabled) |
432 | 432 |
cl_engine_set_num(engine, CL_ENGINE_KEEPTMP, 1); |
433 | 433 |
|
434 |
+ if(optget(opts, "ForceToDisk")->enabled) |
|
435 |
+ cl_engine_set_num(engine, CL_ENGINE_FORCETODISK, 1); |
|
436 |
+ |
|
434 | 437 |
if(optget(opts, "PhishingSignatures")->enabled) |
435 | 438 |
dboptions |= CL_DB_PHISHING; |
436 | 439 |
else |
... | ... |
@@ -631,6 +631,9 @@ int scanmanager(const struct optstruct *opts) |
631 | 631 |
if(optget(opts, "leave-temps")->enabled) |
632 | 632 |
cl_engine_set_num(engine, CL_ENGINE_KEEPTMP, 1); |
633 | 633 |
|
634 |
+ if(optget(opts, "force-to-disk")->enabled) |
|
635 |
+ cl_engine_set_num(engine, CL_ENGINE_FORCETODISK, 1); |
|
636 |
+ |
|
634 | 637 |
if(optget(opts, "bytecode-unsigned")->enabled) |
635 | 638 |
dboptions |= CL_DB_BYTECODE_UNSIGNED; |
636 | 639 |
|
... | ... |
@@ -241,6 +241,10 @@ Example |
241 | 241 |
# Default: yes |
242 | 242 |
#AlgorithmicDetection yes |
243 | 243 |
|
244 |
+# This option causes memory or nested map scans to dump the content to disk. |
|
245 |
+# If you turn on this option, more data is written to disk and is available |
|
246 |
+# when the LeaveTemporaryFiles option is enabled. |
|
247 |
+#ForceToDisk yes |
|
244 | 248 |
|
245 | 249 |
## |
246 | 250 |
## Executable files |
... | ... |
@@ -193,7 +193,8 @@ enum cl_engine_field { |
193 | 193 |
CL_ENGINE_MAX_HTMLNORMALIZE, /* uint64_t */ |
194 | 194 |
CL_ENGINE_MAX_HTMLNOTAGS, /* uint64_t */ |
195 | 195 |
CL_ENGINE_MAX_SCRIPTNORMALIZE, /* uint64_t */ |
196 |
- CL_ENGINE_MAX_ZIPTYPERCG /* uint64_t */ |
|
196 |
+ CL_ENGINE_MAX_ZIPTYPERCG, /* uint64_t */ |
|
197 |
+ CL_ENGINE_FORCETODISK /* uint32_t */ |
|
197 | 198 |
}; |
198 | 199 |
|
199 | 200 |
enum bytecode_security { |
... | ... |
@@ -157,7 +157,7 @@ int cli_scancpio_old(cli_ctx *ctx) |
157 | 157 |
if(ret == CL_EMAXFILES) { |
158 | 158 |
return ret; |
159 | 159 |
} else if(ret == CL_SUCCESS) { |
160 |
- ret = cli_map_scandesc(*ctx->fmap, pos, filesize, ctx); |
|
160 |
+ ret = cli_map_scan(*ctx->fmap, pos, filesize, ctx); |
|
161 | 161 |
if(ret == CL_VIRUS) |
162 | 162 |
return ret; |
163 | 163 |
} |
... | ... |
@@ -234,7 +234,7 @@ int cli_scancpio_odc(cli_ctx *ctx) |
234 | 234 |
if(ret == CL_EMAXFILES) { |
235 | 235 |
return ret; |
236 | 236 |
} else if(ret == CL_SUCCESS) { |
237 |
- ret = cli_map_scandesc(*ctx->fmap, pos, filesize, ctx); |
|
237 |
+ ret = cli_map_scan(*ctx->fmap, pos, filesize, ctx); |
|
238 | 238 |
if(ret == CL_VIRUS) |
239 | 239 |
return ret; |
240 | 240 |
} |
... | ... |
@@ -313,7 +313,7 @@ int cli_scancpio_newc(cli_ctx *ctx, int crc) |
313 | 313 |
if(ret == CL_EMAXFILES) { |
314 | 314 |
return ret; |
315 | 315 |
} else if(ret == CL_SUCCESS) { |
316 |
- ret = cli_map_scandesc(*ctx->fmap, pos, filesize, ctx); |
|
316 |
+ ret = cli_map_scan(*ctx->fmap, pos, filesize, ctx); |
|
317 | 317 |
if(ret == CL_VIRUS) |
318 | 318 |
return ret; |
319 | 319 |
} |
... | ... |
@@ -168,7 +168,7 @@ int cli_scandmg(cli_ctx *ctx) |
168 | 168 |
cli_dbgmsg("cli_scandmg: Extracting into %s\n", dirname); |
169 | 169 |
|
170 | 170 |
/* Dump XML to tempfile, if needed */ |
171 |
- if (ctx->engine->keeptmp) { |
|
171 |
+ if (ctx->engine->keeptmp && !ctx->engine->forcetodisk) { |
|
172 | 172 |
int xret; |
173 | 173 |
xret = dmg_extract_xml(ctx, dirname, &hdr); |
174 | 174 |
|
... | ... |
@@ -180,7 +180,7 @@ int cli_scandmg(cli_ctx *ctx) |
180 | 180 |
} |
181 | 181 |
|
182 | 182 |
/* scan XML with cli_map_scandesc */ |
183 |
- ret = cli_map_scandesc(*ctx->fmap, (off_t)hdr.xmlOffset, (size_t)hdr.xmlLength, ctx); |
|
183 |
+ ret = cli_map_scan(*ctx->fmap, (off_t)hdr.xmlOffset, (size_t)hdr.xmlLength, ctx); |
|
184 | 184 |
if (ret != CL_CLEAN) { |
185 | 185 |
cli_dbgmsg("cli_scandmg: retcode from scanning TOC xml: %s\n", cl_strerror(ret)); |
186 | 186 |
if (!ctx->engine->keeptmp) |
... | ... |
@@ -553,7 +553,7 @@ int cli_scanmacho_unibin(cli_ctx *ctx) |
553 | 553 |
cli_dbgmsg("UNIBIN: Binary %u of %u\n", i + 1, fat_header.nfats); |
554 | 554 |
cli_dbgmsg("UNIBIN: File offset: %u\n", fat_arch.offset); |
555 | 555 |
cli_dbgmsg("UNIBIN: File size: %u\n", fat_arch.size); |
556 |
- ret = cli_map_scandesc(map, fat_arch.offset, fat_arch.size, ctx); |
|
556 |
+ ret = cli_map_scan(map, fat_arch.offset, fat_arch.size, ctx); |
|
557 | 557 |
if(ret == CL_VIRUS) |
558 | 558 |
break; |
559 | 559 |
} |
... | ... |
@@ -461,6 +461,12 @@ int cl_engine_set_num(struct cl_engine *engine, enum cl_engine_field field, long |
461 | 461 |
case CL_ENGINE_KEEPTMP: |
462 | 462 |
engine->keeptmp = num; |
463 | 463 |
break; |
464 |
+ case CL_ENGINE_FORCETODISK: |
|
465 |
+ if(num) |
|
466 |
+ engine->forcetodisk = 1; |
|
467 |
+ else |
|
468 |
+ engine->forcetodisk = 0; |
|
469 |
+ break; |
|
464 | 470 |
case CL_ENGINE_BYTECODE_SECURITY: |
465 | 471 |
if (engine->dboptions & CL_DB_COMPILED) { |
466 | 472 |
cli_errmsg("cl_engine_set_num: CL_ENGINE_BYTECODE_SECURITY cannot be set after engine was compiled\n"); |
... | ... |
@@ -541,6 +547,8 @@ long long cl_engine_get_num(const struct cl_engine *engine, enum cl_engine_field |
541 | 541 |
return engine->ac_maxdepth; |
542 | 542 |
case CL_ENGINE_KEEPTMP: |
543 | 543 |
return engine->keeptmp; |
544 |
+ case CL_ENGINE_FORCETODISK: |
|
545 |
+ return engine->forcetodisk; |
|
544 | 546 |
case CL_ENGINE_BYTECODE_SECURITY: |
545 | 547 |
return engine->bytecode_security; |
546 | 548 |
case CL_ENGINE_BYTECODE_TIMEOUT: |
... | ... |
@@ -619,6 +627,7 @@ struct cl_settings *cl_engine_settings_copy(const struct cl_engine *engine) |
619 | 619 |
settings->ac_maxdepth = engine->ac_maxdepth; |
620 | 620 |
settings->tmpdir = engine->tmpdir ? strdup(engine->tmpdir) : NULL; |
621 | 621 |
settings->keeptmp = engine->keeptmp; |
622 |
+ settings->forcetodisk = engine->forcetodisk; |
|
622 | 623 |
settings->maxscansize = engine->maxscansize; |
623 | 624 |
settings->maxfilesize = engine->maxfilesize; |
624 | 625 |
settings->maxreclevel = engine->maxreclevel; |
... | ... |
@@ -652,6 +661,7 @@ int cl_engine_settings_apply(struct cl_engine *engine, const struct cl_settings |
652 | 652 |
engine->ac_mindepth = settings->ac_mindepth; |
653 | 653 |
engine->ac_maxdepth = settings->ac_maxdepth; |
654 | 654 |
engine->keeptmp = settings->keeptmp; |
655 |
+ engine->forcetodisk = settings->forcetodisk; |
|
655 | 656 |
engine->maxscansize = settings->maxscansize; |
656 | 657 |
engine->maxfilesize = settings->maxfilesize; |
657 | 658 |
engine->maxreclevel = settings->maxreclevel; |
... | ... |
@@ -55,7 +55,7 @@ |
55 | 55 |
* in re-enabling affected modules. |
56 | 56 |
*/ |
57 | 57 |
|
58 |
-#define CL_FLEVEL 75 |
|
58 |
+#define CL_FLEVEL 77 |
|
59 | 59 |
#define CL_FLEVEL_DCONF CL_FLEVEL |
60 | 60 |
#define CL_FLEVEL_SIGTOOL CL_FLEVEL |
61 | 61 |
|
... | ... |
@@ -283,6 +283,8 @@ struct cl_engine { |
283 | 283 |
uint64_t maxhtmlnotags; /* max size for scanning normalized HTML */ |
284 | 284 |
uint64_t maxscriptnormalize; /* max size to normalize scripts */ |
285 | 285 |
uint64_t maxziptypercg; /* max size to re-do zip filetype */ |
286 |
+ |
|
287 |
+ uint32_t forcetodisk; /* cause memory or map scans to dump to disk first */ |
|
286 | 288 |
}; |
287 | 289 |
|
288 | 290 |
struct cl_settings { |
... | ... |
@@ -322,6 +324,8 @@ struct cl_settings { |
322 | 322 |
uint64_t maxhtmlnotags; /* max size for scanning normalized HTML */ |
323 | 323 |
uint64_t maxscriptnormalize; /* max size to normalize scripts */ |
324 | 324 |
uint64_t maxziptypercg; /* max size to re-do zip filetype */ |
325 |
+ |
|
326 |
+ uint32_t forcetodisk; /* cause memory or map scans to dump to disk first */ |
|
325 | 327 |
}; |
326 | 328 |
|
327 | 329 |
extern int (*cli_unrar_open)(int fd, const char *dirname, unrar_state_t *state); |
... | ... |
@@ -2964,7 +2964,67 @@ int cl_scandesc(int desc, const char **virname, unsigned long int *scanned, cons |
2964 | 2964 |
return cl_scandesc_callback(desc, virname, scanned, engine, scanoptions, NULL); |
2965 | 2965 |
} |
2966 | 2966 |
|
2967 |
-/* length = 0, till the end */ |
|
2967 |
+/* For map scans that may be forced to disk */ |
|
2968 |
+int cli_map_scan(cl_fmap_t *map, off_t offset, size_t length, cli_ctx *ctx) |
|
2969 |
+{ |
|
2970 |
+ off_t old_off = map->nested_offset; |
|
2971 |
+ size_t old_len = map->len; |
|
2972 |
+ int ret = CL_CLEAN; |
|
2973 |
+ |
|
2974 |
+ cli_dbgmsg("cli_map_scan: [%ld, +%lu)\n", |
|
2975 |
+ (long)offset, (unsigned long)length); |
|
2976 |
+ if (offset < 0 || offset >= map->len) { |
|
2977 |
+ cli_dbgmsg("Invalid offset: %ld\n", (long)offset); |
|
2978 |
+ return CL_CLEAN; |
|
2979 |
+ } |
|
2980 |
+ |
|
2981 |
+ if (ctx->engine->forcetodisk) { |
|
2982 |
+ /* if this is forced to disk, then need to write the nested map and scan it */ |
|
2983 |
+ const uint8_t *mapdata = NULL; |
|
2984 |
+ char *tempfile = NULL; |
|
2985 |
+ int fd = -1; |
|
2986 |
+ size_t nread = 0; |
|
2987 |
+ |
|
2988 |
+ mapdata = fmap_need_off_once_len(map, offset, length, &nread); |
|
2989 |
+ if (!mapdata || (nread != length)) { |
|
2990 |
+ cli_errmsg("cli_map_scan: could not map sub-file\n"); |
|
2991 |
+ return CL_EMAP; |
|
2992 |
+ } |
|
2993 |
+ |
|
2994 |
+ ret = cli_gentempfd(ctx->engine->tmpdir, &tempfile, &fd); |
|
2995 |
+ if (ret != CL_SUCCESS) { |
|
2996 |
+ return ret; |
|
2997 |
+ } |
|
2998 |
+ |
|
2999 |
+ cli_dbgmsg("cli_map_scan: writing nested map content to temp file %s\n", tempfile); |
|
3000 |
+ if (cli_writen(fd, mapdata, length) < 0) { |
|
3001 |
+ cli_errmsg("cli_map_scan: cli_writen error writing subdoc temporary file.\n"); |
|
3002 |
+ ret = CL_EWRITE; |
|
3003 |
+ } |
|
3004 |
+ |
|
3005 |
+ /* scan the temp file */ |
|
3006 |
+ ret = cli_base_scandesc(fd, ctx, CL_TYPE_ANY); |
|
3007 |
+ |
|
3008 |
+ /* remove the temp file, if needed */ |
|
3009 |
+ if (fd > -1) { |
|
3010 |
+ close(fd); |
|
3011 |
+ } |
|
3012 |
+ if(!ctx->engine->keeptmp) { |
|
3013 |
+ if (cli_unlink(tempfile)) { |
|
3014 |
+ cli_errmsg("cli_map_scan: error unlinking tempfile %s\n", tempfile); |
|
3015 |
+ ret = CL_EUNLINK; |
|
3016 |
+ } |
|
3017 |
+ } |
|
3018 |
+ free(tempfile); |
|
3019 |
+ } |
|
3020 |
+ else { |
|
3021 |
+ /* Not forced to disk, use nested map */ |
|
3022 |
+ ret = cli_map_scandesc(map, offset, length, ctx); |
|
3023 |
+ } |
|
3024 |
+ return ret; |
|
3025 |
+} |
|
3026 |
+ |
|
3027 |
+/* For map scans that are not forced to disk */ |
|
2968 | 3028 |
int cli_map_scandesc(cl_fmap_t *map, off_t offset, size_t length, cli_ctx *ctx) |
2969 | 3029 |
{ |
2970 | 3030 |
off_t old_off = map->nested_offset; |
... | ... |
@@ -29,6 +29,7 @@ int cli_magic_scandesc(int desc, cli_ctx *ctx); |
29 | 29 |
int cli_partition_scandesc(int desc, cli_ctx *ctx); |
30 | 30 |
int cli_magic_scandesc_type(cli_ctx *ctx, cli_file_t type); |
31 | 31 |
int cli_map_scandesc(cl_fmap_t *map, off_t offset, size_t length, cli_ctx *ctx); |
32 |
+int cli_map_scan(cl_fmap_t *map, off_t offset, size_t length, cli_ctx *ctx); |
|
32 | 33 |
int cli_mem_scandesc(const void *buffer, size_t length, cli_ctx *ctx); |
33 | 34 |
int cli_found_possibly_unwanted(cli_ctx* ctx); |
34 | 35 |
|
... | ... |
@@ -338,6 +338,8 @@ const struct clam_option __clam_options[] = { |
338 | 338 |
|
339 | 339 |
{ "ArchiveBlockEncrypted", "block-encrypted", 0, TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMD | OPT_CLAMSCAN, "Mark encrypted archives as viruses (Encrypted.Zip, Encrypted.RAR).", "no" }, |
340 | 340 |
|
341 |
+ { "ForceToDisk", "force-to-disk", 0, TYPE_BOOL, MATCH_BOOL, 0, NULL, 0, OPT_CLAMD | OPT_CLAMSCAN, "This option causes memory or nested map scans to dump the content to disk.\nIf you turn on this option, more data is written to disk and is available\nwhen the leave-temps option is enabled at the cost of more disk writes.", "no" }, |
|
342 |
+ |
|
341 | 343 |
{ "MaxScanSize", "max-scansize", 0, 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.", "100M" }, |
342 | 344 |
|
343 | 345 |
{ "MaxFileSize", "max-filesize", 0, 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.", "25M" }, |