... | ... |
@@ -1,3 +1,8 @@ |
1 |
+Fri Oct 2 21:01:51 CEST 2009 (tk) |
|
2 |
+---------------------------------- |
|
3 |
+ * libclamav: check file sizes for MD5 sigs in all cases |
|
4 |
+ Reported by Edwin |
|
5 |
+ |
|
1 | 6 |
Fri Oct 2 14:35:42 CEST 2009 (tk) |
2 | 7 |
---------------------------------- |
3 | 8 |
* libclamav: unify fp checking; output fp signatures in debug mode |
... | ... |
@@ -245,7 +245,7 @@ void cli_bm_free(struct cli_matcher *root) |
245 | 245 |
} |
246 | 246 |
} |
247 | 247 |
|
248 |
-int cli_bm_scanbuff(const unsigned char *buffer, uint32_t length, const char **virname, const struct cli_matcher *root, uint32_t offset, int fd, struct cli_bm_off *offdata) |
|
248 |
+int cli_bm_scanbuff(const unsigned char *buffer, uint32_t length, const char **virname, const struct cli_bm_patt **patt, const struct cli_matcher *root, uint32_t offset, int fd, struct cli_bm_off *offdata) |
|
249 | 249 |
{ |
250 | 250 |
uint32_t i, j, off, off_min, off_max; |
251 | 251 |
uint8_t found, pchain, shift; |
... | ... |
@@ -370,6 +370,8 @@ int cli_bm_scanbuff(const unsigned char *buffer, uint32_t length, const char **v |
370 | 370 |
} |
371 | 371 |
if(virname) |
372 | 372 |
*virname = p->virname; |
373 |
+ if(patt) |
|
374 |
+ *patt = p; |
|
373 | 375 |
if(info.exeinfo.section) |
374 | 376 |
free(info.exeinfo.section); |
375 | 377 |
return CL_VIRUS; |
... | ... |
@@ -35,7 +35,7 @@ struct cli_bm_patt { |
35 | 35 |
uint16_t length, prefix_length; |
36 | 36 |
uint16_t cnt; |
37 | 37 |
unsigned char pattern0; |
38 |
- uint32_t boundary; |
|
38 |
+ uint32_t boundary, filesize; |
|
39 | 39 |
}; |
40 | 40 |
|
41 | 41 |
struct cli_bm_off { |
... | ... |
@@ -46,7 +46,7 @@ int cli_bm_addpatt(struct cli_matcher *root, struct cli_bm_patt *pattern, const |
46 | 46 |
int cli_bm_init(struct cli_matcher *root); |
47 | 47 |
int cli_bm_initoff(const struct cli_matcher *root, struct cli_bm_off *data, int fd); |
48 | 48 |
void cli_bm_freeoff(struct cli_bm_off *data, const struct cli_matcher *root); |
49 |
-int cli_bm_scanbuff(const unsigned char *buffer, uint32_t length, const char **virname, const struct cli_matcher *root, uint32_t offset, int fd, struct cli_bm_off *offdata); |
|
49 |
+int cli_bm_scanbuff(const unsigned char *buffer, uint32_t length, const char **virname, const struct cli_bm_patt **patt, const struct cli_matcher *root, uint32_t offset, int fd, struct cli_bm_off *offdata); |
|
50 | 50 |
void cli_bm_free(struct cli_matcher *root); |
51 | 51 |
|
52 | 52 |
#endif |
... | ... |
@@ -76,7 +76,7 @@ int cli_scanbuff(const unsigned char *buffer, uint32_t length, uint32_t offset, |
76 | 76 |
if(!acdata && (ret = cli_ac_initdata(&mdata, troot->ac_partsigs, troot->ac_lsigs, troot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN))) |
77 | 77 |
return ret; |
78 | 78 |
|
79 |
- if(troot->ac_only || (ret = cli_bm_scanbuff(buffer, length, virname, troot, offset, -1, NULL)) != CL_VIRUS) |
|
79 |
+ if(troot->ac_only || (ret = cli_bm_scanbuff(buffer, length, virname, NULL, troot, offset, -1, NULL)) != CL_VIRUS) |
|
80 | 80 |
ret = cli_ac_scanbuff(buffer, length, virname, NULL, NULL, troot, acdata ? (acdata[0]) : (&mdata), offset, ftype, NULL, AC_SCAN_VIR, NULL); |
81 | 81 |
|
82 | 82 |
if(!acdata) |
... | ... |
@@ -89,7 +89,7 @@ int cli_scanbuff(const unsigned char *buffer, uint32_t length, uint32_t offset, |
89 | 89 |
if(!acdata && (ret = cli_ac_initdata(&mdata, groot->ac_partsigs, groot->ac_lsigs, groot->ac_reloff_num, CLI_DEFAULT_AC_TRACKLEN))) |
90 | 90 |
return ret; |
91 | 91 |
|
92 |
- if(groot->ac_only || (ret = cli_bm_scanbuff(buffer, length, virname, groot, offset, -1, NULL)) != CL_VIRUS) |
|
92 |
+ if(groot->ac_only || (ret = cli_bm_scanbuff(buffer, length, virname, NULL, groot, offset, -1, NULL)) != CL_VIRUS) |
|
93 | 93 |
ret = cli_ac_scanbuff(buffer, length, virname, NULL, NULL, groot, acdata ? (acdata[1]) : (&mdata), offset, ftype, NULL, AC_SCAN_VIR, NULL); |
94 | 94 |
|
95 | 95 |
if(!acdata) |
... | ... |
@@ -292,6 +292,7 @@ int cli_checkfp(int fd, cli_ctx *ctx) |
292 | 292 |
const char *virname; |
293 | 293 |
off_t pos; |
294 | 294 |
struct stat sb; |
295 |
+ const struct cli_bm_patt *patt = NULL; |
|
295 | 296 |
|
296 | 297 |
|
297 | 298 |
if((pos = lseek(fd, 0, SEEK_CUR)) == -1) { |
... | ... |
@@ -302,25 +303,29 @@ int cli_checkfp(int fd, cli_ctx *ctx) |
302 | 302 |
lseek(fd, 0, SEEK_SET); |
303 | 303 |
|
304 | 304 |
if(ctx->engine->md5_fp) { |
305 |
+ if(fstat(fd, &sb) == -1) { |
|
306 |
+ cli_errmsg("cli_checkfp(): fstat(%d) failed\n", fd); |
|
307 |
+ lseek(fd, pos, SEEK_SET); |
|
308 |
+ return 0; |
|
309 |
+ } |
|
310 |
+ |
|
305 | 311 |
if(!(digest = cli_md5digest(fd))) { |
306 | 312 |
cli_errmsg("cli_checkfp(): Can't generate MD5 checksum\n"); |
307 | 313 |
lseek(fd, pos, SEEK_SET); |
308 | 314 |
return 0; |
309 | 315 |
} |
310 | 316 |
|
311 |
- if(cli_bm_scanbuff(digest, 16, &virname, ctx->engine->md5_fp, 0, -1, NULL) == CL_VIRUS) { |
|
317 |
+ if(cli_bm_scanbuff(digest, 16, &virname, &patt, ctx->engine->md5_fp, 0, -1, NULL) == CL_VIRUS && patt->filesize == sb.st_size) { |
|
312 | 318 |
cli_dbgmsg("cli_checkfp(): Found false positive detection (fp sig: %s)\n", virname); |
313 | 319 |
free(digest); |
314 | 320 |
lseek(fd, pos, SEEK_SET); |
315 | 321 |
return 1; |
316 | 322 |
} |
317 | 323 |
|
318 |
- if(fstat(fd, &sb) != -1) { |
|
319 |
- for(i = 0; i < 16; i++) |
|
320 |
- sprintf(md5 + i * 2, "%02x", digest[i]); |
|
321 |
- md5[32] = 0; |
|
322 |
- cli_dbgmsg("FP SIGNATURE: %s:%u:%s\n", md5, (unsigned int) sb.st_size, *ctx->virname ? *ctx->virname : "Name"); |
|
323 |
- } |
|
324 |
+ for(i = 0; i < 16; i++) |
|
325 |
+ sprintf(md5 + i * 2, "%02x", digest[i]); |
|
326 |
+ md5[32] = 0; |
|
327 |
+ cli_dbgmsg("FP SIGNATURE: %s:%u:%s\n", md5, (unsigned int) sb.st_size, *ctx->virname ? *ctx->virname : "Name"); |
|
324 | 328 |
|
325 | 329 |
free(digest); |
326 | 330 |
} |
... | ... |
@@ -425,7 +430,7 @@ int cli_scandesc(int desc, cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struc |
425 | 425 |
length += maxpatlen; |
426 | 426 |
|
427 | 427 |
if(troot) { |
428 |
- if(troot->ac_only || (ret = cli_bm_scanbuff(upt, length, ctx->virname, troot, offset, desc, bm_offmode ? &toff : NULL)) != CL_VIRUS) |
|
428 |
+ if(troot->ac_only || (ret = cli_bm_scanbuff(upt, length, ctx->virname, NULL, troot, offset, desc, bm_offmode ? &toff : NULL)) != CL_VIRUS) |
|
429 | 429 |
ret = cli_ac_scanbuff(upt, length, ctx->virname, NULL, NULL, troot, &tdata, offset, ftype, ftoffset, acmode, NULL); |
430 | 430 |
|
431 | 431 |
if(ret == CL_VIRUS) { |
... | ... |
@@ -440,7 +445,7 @@ int cli_scandesc(int desc, cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struc |
440 | 440 |
} |
441 | 441 |
|
442 | 442 |
if(!ftonly) { |
443 |
- if(groot->ac_only || (ret = cli_bm_scanbuff(upt, length, ctx->virname, groot, offset, desc, NULL)) != CL_VIRUS) |
|
443 |
+ if(groot->ac_only || (ret = cli_bm_scanbuff(upt, length, ctx->virname, NULL, groot, offset, desc, NULL)) != CL_VIRUS) |
|
444 | 444 |
ret = cli_ac_scanbuff(upt, length, ctx->virname, NULL, NULL, groot, &gdata, offset, ftype, ftoffset, acmode, NULL); |
445 | 445 |
|
446 | 446 |
if(ret == CL_VIRUS) { |
... | ... |
@@ -514,8 +519,10 @@ int cli_scandesc(int desc, cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struc |
514 | 514 |
return CL_VIRUS; |
515 | 515 |
|
516 | 516 |
if(!ftonly && ctx->engine->md5_hdb) { |
517 |
+ const struct cli_bm_patt *patt; |
|
517 | 518 |
cli_md5_final(digest, &md5ctx); |
518 |
- if(cli_bm_scanbuff(digest, 16, ctx->virname, ctx->engine->md5_hdb, 0, -1, NULL) == CL_VIRUS && (cli_bm_scanbuff(digest, 16, NULL, ctx->engine->md5_fp, 0, -1, NULL) != CL_VIRUS)) |
|
519 |
+ fstat(desc, &sb); |
|
520 |
+ if(cli_bm_scanbuff(digest, 16, ctx->virname, &patt, ctx->engine->md5_hdb, 0, -1, NULL) == CL_VIRUS && patt->filesize == sb.st_size && (cli_bm_scanbuff(digest, 16, NULL, &patt, ctx->engine->md5_fp, 0, -1, NULL) != CL_VIRUS || patt->filesize != sb.st_size)) |
|
519 | 521 |
return CL_VIRUS; |
520 | 522 |
} |
521 | 523 |
|
... | ... |
@@ -924,8 +924,9 @@ int cli_scanpe(int desc, cli_ctx *ctx) |
924 | 924 |
for(j = 0; j < md5_sect->soff_len && md5_sect->soff[j] <= exe_sections[i].rsz; j++) { |
925 | 925 |
if(md5_sect->soff[j] == exe_sections[i].rsz) { |
926 | 926 |
unsigned char md5_dig[16]; |
927 |
- if(cli_md5sect(desc, &exe_sections[i], md5_dig) && cli_bm_scanbuff(md5_dig, 16, ctx->virname, ctx->engine->md5_mdb, 0, -1, NULL) == CL_VIRUS) { |
|
928 |
- if(cli_bm_scanbuff(md5_dig, 16, NULL, ctx->engine->md5_fp, 0, -1, NULL) != CL_VIRUS) { |
|
927 |
+ const struct cli_bm_patt *patt; |
|
928 |
+ if(cli_md5sect(desc, &exe_sections[i], md5_dig) && cli_bm_scanbuff(md5_dig, 16, ctx->virname, &patt, ctx->engine->md5_mdb, 0, -1, NULL) == CL_VIRUS && patt->filesize == exe_sections[i].rsz) { |
|
929 |
+ if(cli_bm_scanbuff(md5_dig, 16, NULL, &patt, ctx->engine->md5_fp, 0, -1, NULL) != CL_VIRUS || patt->filesize != fsize) { |
|
929 | 930 |
|
930 | 931 |
free(section_hdr); |
931 | 932 |
free(exe_sections); |
... | ... |
@@ -1194,13 +1194,13 @@ static int hash_match(const struct regex_matcher *rlist, const char *host, size_ |
1194 | 1194 |
h[64]='\0'; |
1195 | 1195 |
cli_dbgmsg("Looking up hash %s for %s(%u)%s(%u)\n", h, host, (unsigned)hlen, path, (unsigned)plen); |
1196 | 1196 |
if (prefix_matched) { |
1197 |
- if (cli_bm_scanbuff(sha256_dig, 4, &virname, &rlist->hostkey_prefix,0,-1,NULL) == CL_VIRUS) { |
|
1197 |
+ if (cli_bm_scanbuff(sha256_dig, 4, &virname, NULL, &rlist->hostkey_prefix,0,-1,NULL) == CL_VIRUS) { |
|
1198 | 1198 |
cli_dbgmsg("prefix matched\n"); |
1199 | 1199 |
*prefix_matched = 1; |
1200 | 1200 |
} else |
1201 | 1201 |
return CL_SUCCESS; |
1202 | 1202 |
} |
1203 |
- if (cli_bm_scanbuff(sha256_dig, 32, &virname, &rlist->sha256_hashes,0,-1,NULL) == CL_VIRUS) { |
|
1203 |
+ if (cli_bm_scanbuff(sha256_dig, 32, &virname, NULL, &rlist->sha256_hashes,0,-1,NULL) == CL_VIRUS) { |
|
1204 | 1204 |
cli_dbgmsg("This hash matched: %s\n", h); |
1205 | 1205 |
switch(*virname) { |
1206 | 1206 |
case 'W': |
... | ... |
@@ -406,7 +406,7 @@ static int cli_chkign(const struct cli_matcher *ignored, const char *signame, co |
406 | 406 |
if(!ignored || !signame || !entry) |
407 | 407 |
return 0; |
408 | 408 |
|
409 |
- if(cli_bm_scanbuff(signame, strlen(signame), &md5_expected, ignored, 0, -1, NULL) == CL_VIRUS) { |
|
409 |
+ if(cli_bm_scanbuff(signame, strlen(signame), &md5_expected, NULL, ignored, 0, -1, NULL) == CL_VIRUS) { |
|
410 | 410 |
if(md5_expected) { |
411 | 411 |
cli_md5_init(&md5ctx); |
412 | 412 |
cli_md5_update(&md5ctx, entry, strlen(entry)); |
... | ... |
@@ -1289,7 +1289,6 @@ static int cli_loadmd5(FILE *fs, struct cl_engine *engine, unsigned int *signo, |
1289 | 1289 |
const char *pt; |
1290 | 1290 |
int ret = CL_SUCCESS; |
1291 | 1291 |
unsigned int size_field = 1, md5_field = 0, line = 0, sigs = 0, tokens_count; |
1292 |
- uint32_t size; |
|
1293 | 1292 |
struct cli_bm_patt *new; |
1294 | 1293 |
struct cli_matcher *db = NULL; |
1295 | 1294 |
|
... | ... |
@@ -1343,7 +1342,7 @@ static int cli_loadmd5(FILE *fs, struct cl_engine *engine, unsigned int *signo, |
1343 | 1343 |
} |
1344 | 1344 |
new->length = 16; |
1345 | 1345 |
|
1346 |
- size = atoi(tokens[size_field]); |
|
1346 |
+ new->filesize = atoi(tokens[size_field]); |
|
1347 | 1347 |
|
1348 | 1348 |
new->virname = cli_mpool_virname(engine->mempool, (char *) tokens[2], options & CL_DB_OFFICIAL); |
1349 | 1349 |
if(!new->virname) { |
... | ... |
@@ -1375,7 +1374,7 @@ static int cli_loadmd5(FILE *fs, struct cl_engine *engine, unsigned int *signo, |
1375 | 1375 |
if(!db->md5_sizes_hs.capacity) { |
1376 | 1376 |
cli_hashset_init(&db->md5_sizes_hs, 65536, 80); |
1377 | 1377 |
} |
1378 |
- cli_hashset_addkey(&db->md5_sizes_hs, size); |
|
1378 |
+ cli_hashset_addkey(&db->md5_sizes_hs, new->filesize); |
|
1379 | 1379 |
} |
1380 | 1380 |
|
1381 | 1381 |
sigs++; |
... | ... |
@@ -455,7 +455,7 @@ static int add_hash(struct regex_matcher *matcher, char* pattern, const char fl, |
455 | 455 |
|
456 | 456 |
if (fl != 'W' && pat->length == 32 && |
457 | 457 |
cli_hashset_contains(&matcher->sha256_pfx_set, cli_readint32(pat->pattern)) && |
458 |
- cli_bm_scanbuff(pat->pattern, 32, &vname, &matcher->sha256_hashes,0,-1,NULL) == CL_VIRUS) { |
|
458 |
+ cli_bm_scanbuff(pat->pattern, 32, &vname, NULL, &matcher->sha256_hashes,0,-1,NULL) == CL_VIRUS) { |
|
459 | 459 |
if (*vname == 'W') { |
460 | 460 |
/* hash is whitelisted in local.gdb */ |
461 | 461 |
cli_dbgmsg("Skipping hash %s\n", pattern); |
... | ... |
@@ -116,7 +116,7 @@ START_TEST (test_bm_scanbuff) { |
116 | 116 |
ret = cli_parse_add(root, "Sig3", "babedead", 0, 0, "*", 0, NULL, 0); |
117 | 117 |
fail_unless(ret == CL_SUCCESS, "cli_parse_add() failed"); |
118 | 118 |
|
119 |
- ret = cli_bm_scanbuff("blah\xde\xad\xbe\xef", 12, &virname, root, 0, -1,NULL); |
|
119 |
+ ret = cli_bm_scanbuff("blah\xde\xad\xbe\xef", 12, &virname, NULL, root, 0, -1, NULL); |
|
120 | 120 |
fail_unless(ret == CL_VIRUS, "cli_bm_scanbuff() failed"); |
121 | 121 |
fail_unless(!strncmp(virname, "Sig2", 4), "Incorrect signature matched in cli_bm_scanbuff()\n"); |
122 | 122 |
cli_bm_free(root); |