Browse code

libclamav: lsigs: handle extended block modifiers (bb#896)

git-svn: trunk@3998

Tomasz Kojm authored on 2008/07/27 00:48:08
Showing 5 changed files
... ...
@@ -1,3 +1,7 @@
1
+Sat Jul 26 17:30:02 CEST 2008 (tk)
2
+----------------------------------
3
+  * libclamav: lsigs: handle extended block modifiers (bb#896)
4
+
1 5
 Fri Jul 25 20:41:21 CEST 2008 (tk)
2 6
 ----------------------------------
3 7
   * libclamav: add initial support for logical signatures (bb#896)
... ...
@@ -377,10 +377,11 @@ void cli_ac_free(struct cli_matcher *root)
377 377
 /*
378 378
  * In parse_only mode this function returns -1 on error or the max subsig id
379 379
  */
380
-int cli_ac_chklsig(const char *expr, const char *end, uint32_t *lsigcnt, unsigned int *cnt, unsigned int parse_only)
380
+int cli_ac_chklsig(const char *expr, const char *end, uint32_t *lsigcnt, unsigned int *cnt, uint64_t *ids, unsigned int parse_only)
381 381
 {
382 382
 	unsigned int i, len = end - expr, pth = 0, opoff = 0, op1off = 0, val;
383
-	unsigned int blkend = 0, id, modval, lcnt = 0, rcnt = 0, tcnt, modoff = 0;
383
+	unsigned int blkend = 0, id, modval1, modval2 = 0, lcnt = 0, rcnt = 0, tcnt, modoff = 0;
384
+	uint64_t lids = 0, rids = 0, tids;
384 385
 	int ret, lval, rval;
385 386
 	char op = 0, op1 = 0, mod = 0, blkmod = 0;
386 387
 	const char *lstart = expr, *lend = NULL, *rstart = NULL, *rend = end, *pt;
... ...
@@ -425,12 +426,14 @@ int cli_ac_chklsig(const char *expr, const char *end, uint32_t *lsigcnt, unsigne
425 425
 	    blkend = i;
426 426
 	    if(expr[i + 1] == '>' || expr[i + 1] == '<' || expr[i + 1] == '=') {
427 427
 		blkmod = expr[i + 1];
428
-		ret = sscanf(&expr[i + 2], "%u", &modval);
428
+		ret = sscanf(&expr[i + 2], "%u,%u", &modval1, &modval2);
429
+		if(ret != 2)
430
+		    ret = sscanf(&expr[i + 2], "%u", &modval1);
429 431
 		if(!ret || ret == EOF) {
430 432
 		    cli_errmsg("chklexpr: Syntax error: Missing number after '%c'\n", expr[i + 1]);
431 433
 		    return -1;
432 434
 		}
433
-		for(i += 2; i + 1 < len && isdigit(expr[i + 1]); i++);
435
+		for(i += 2; i + 1 < len && (isdigit(expr[i + 1]) || expr[i + 1] == ','); i++);
434 436
 	    }
435 437
 
436 438
 	    if(&expr[i + 1] == rend)
... ...
@@ -447,7 +450,7 @@ int cli_ac_chklsig(const char *expr, const char *end, uint32_t *lsigcnt, unsigne
447 447
 
448 448
     if(!op && !op1) {
449 449
 	if(expr[0] == '(')
450
-	    return cli_ac_chklsig(++expr, --end, lsigcnt, cnt, parse_only);
450
+	    return cli_ac_chklsig(++expr, --end, lsigcnt, cnt, ids, parse_only);
451 451
 
452 452
 	ret = sscanf(expr, "%u", &id);
453 453
 	if(!ret || ret == EOF) {
... ...
@@ -462,43 +465,44 @@ int cli_ac_chklsig(const char *expr, const char *end, uint32_t *lsigcnt, unsigne
462 462
 
463 463
 	if(mod) {
464 464
 	    pt = strchr(expr, mod) + modoff;
465
-	    ret = sscanf(pt, "%u", &modval);
465
+	    ret = sscanf(pt, "%u", &modval1);
466 466
 	    if(!ret || ret == EOF) {
467 467
 		cli_errmsg("chklexpr: Syntax error: Missing number after '%c'\n", mod);
468 468
 		return -1;
469 469
 	    }
470
-	    if(!parse_only) switch(mod) {
471
-		case '=':
472
-		    if(val == modval) {
473
-			*cnt += val;
474
-			return 1;
475
-		    } else {
470
+	    if(!parse_only) {
471
+		switch(mod) {
472
+		    case '=':
473
+			if(val != modval1)
474
+			    return 0;
475
+			break;
476
+		    case '<':
477
+			if(val >= modval1)
478
+			    return 0;
479
+			break;
480
+		    case '>':
481
+			if(val <= modval1)
482
+			    return 0;
483
+			break;
484
+		    default:
476 485
 			return 0;
477
-		    }
478
-		    break;
479
-		case '<':
480
-		    if(val < modval) {
481
-			*cnt += val;
482
-			return 1;
483
-		    } else {
484
-			return 0;
485
-		    }
486
-		    break;
487
-		case '>':
488
-		    if(val > modval) {
489
-			*cnt += val;
490
-			return 1;
491
-		    } else {
492
-			return 0;
493
-		    }
486
+		}
487
+		*cnt += val;
488
+		*ids |= (uint64_t) 1 << id;
489
+		return 1;
494 490
 	    }
495 491
 	}
496 492
 
497 493
 	if(parse_only) {
498 494
 	    return val;
499 495
 	} else {
500
-	    *cnt += val;
501
-	    return val ? 1 : 0;
496
+	    if(val) {
497
+		*cnt += val;
498
+		*ids |= (uint64_t) 1 << id;
499
+		return 1;
500
+	    } else {
501
+		return 0;
502
+	    }
502 503
 	}
503 504
     }
504 505
 
... ...
@@ -520,13 +524,13 @@ int cli_ac_chklsig(const char *expr, const char *end, uint32_t *lsigcnt, unsigne
520 520
     }
521 521
     rstart = &expr[opoff + 1];
522 522
 
523
-    lval = cli_ac_chklsig(lstart, lend, lsigcnt, &lcnt, parse_only);
523
+    lval = cli_ac_chklsig(lstart, lend, lsigcnt, &lcnt, &lids, parse_only);
524 524
     if(lval == -1) {
525 525
 	cli_errmsg("cli_ac_chklsig: Calculation of lval failed\n");
526 526
 	return -1;
527 527
     }
528 528
 
529
-    rval = cli_ac_chklsig(rstart, rend, lsigcnt, &rcnt, parse_only);
529
+    rval = cli_ac_chklsig(rstart, rend, lsigcnt, &rcnt, &rids, parse_only);
530 530
     if(rval == -1) {
531 531
 	cli_errmsg("cli_ac_chklsig: Calculation of rval failed\n");
532 532
 	return -1;
... ...
@@ -555,43 +559,48 @@ int cli_ac_chklsig(const char *expr, const char *end, uint32_t *lsigcnt, unsigne
555 555
 	}
556 556
 
557 557
 	if(!blkmod) {
558
-	    if(ret)
558
+	    if(ret) {
559 559
 		*cnt += lcnt + rcnt;
560
-
560
+		*ids |= lids | rids;
561
+	    }
561 562
 	    return ret;
562 563
 	} else {
563
-	    if(ret)
564
+	    if(ret) {
564 565
 		tcnt = lcnt + rcnt;
565
-	    else
566
+		tids = lids | rids;
567
+	    } else {
566 568
 		tcnt = 0;
569
+		tids = 0;
570
+	    }
567 571
 
568 572
 	    switch(blkmod) {
569 573
 		case '=':
570
-		    if(tcnt == modval) {
571
-			*cnt += tcnt;
572
-			return 1;
573
-		    } else {
574
+		    if(tcnt != modval1)
574 575
 			return 0;
575
-		    }
576 576
 		    break;
577 577
 		case '<':
578
-		    if(tcnt < modval) {
579
-			*cnt += tcnt;
580
-			return 1;
581
-		    } else {
578
+		    if(tcnt >= modval1)
582 579
 			return 0;
583
-		    }
584 580
 		    break;
585 581
 		case '>':
586
-		    if(tcnt > modval) {
587
-			*cnt += tcnt;
588
-			return 1;
589
-		    } else {
582
+		    if(tcnt <= modval1)
590 583
 			return 0;
591
-		    }
584
+		    break;
592 585
 		default:
593 586
 		    return 0;
594 587
 	    }
588
+
589
+	    if(modval2) {
590
+		val = 0;
591
+		while(tids) {
592
+		    val += tids & (uint64_t) 1;
593
+		    tids >>= 1;
594
+		}
595
+		if(val < modval2)
596
+		    return 0;
597
+	    }
598
+	    *cnt += tcnt;
599
+	    return 1;
595 600
 	}
596 601
     }
597 602
 }
... ...
@@ -76,7 +76,7 @@ struct cli_ac_node {
76 76
 
77 77
 int cli_ac_addpatt(struct cli_matcher *root, struct cli_ac_patt *pattern);
78 78
 int cli_ac_initdata(struct cli_ac_data *data, uint32_t partsigs, uint32_t lsigs, uint8_t tracklen);
79
-int cli_ac_chklsig(const char *expr, const char *end, uint32_t *lsigcnt, unsigned int *cnt, unsigned int parse_only);
79
+int cli_ac_chklsig(const char *expr, const char *end, uint32_t *lsigcnt, unsigned int *cnt, uint64_t *ids, unsigned int parse_only);
80 80
 void cli_ac_freedata(struct cli_ac_data *data);
81 81
 int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **virname, void **customdata, const struct cli_matcher *root, struct cli_ac_data *mdata, uint32_t offset, cli_file_t ftype, int fd, struct cli_matched_type **ftoffset, unsigned int mode, const cli_ctx *ctx);
82 82
 int cli_ac_buildtrie(struct cli_matcher *root);
... ...
@@ -254,6 +254,7 @@ int cli_scandesc(int desc, cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struc
254 254
 	int ret = CL_CLEAN, type = CL_CLEAN, bytes;
255 255
 	unsigned int i, evalcnt;
256 256
 	uint32_t buffersize, length, maxpatlen, shift = 0, offset = 0;
257
+	uint64_t evalids;
257 258
 	struct cli_ac_data gdata, tdata;
258 259
 	cli_md5_ctx md5ctx;
259 260
 	unsigned char digest[16];
... ...
@@ -386,7 +387,8 @@ int cli_scandesc(int desc, cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struc
386 386
     if(troot) {
387 387
 	for(i = 0; i < troot->ac_lsigs; i++) {
388 388
 	    evalcnt = 0;
389
-	    if(cli_ac_chklsig(troot->ac_lsigtable[i]->logic, troot->ac_lsigtable[i]->logic + strlen(troot->ac_lsigtable[i]->logic), tdata.lsigcnt[i], &evalcnt, 0) == 1) {
389
+	    evalids = 0;
390
+	    if(cli_ac_chklsig(troot->ac_lsigtable[i]->logic, troot->ac_lsigtable[i]->logic + strlen(troot->ac_lsigtable[i]->logic), tdata.lsigcnt[i], &evalcnt, &evalids, 0) == 1) {
390 391
 		if(ctx->virname)
391 392
 		    *ctx->virname = troot->ac_lsigtable[i]->virname;
392 393
 		ret = CL_VIRUS;
... ...
@@ -399,7 +401,8 @@ int cli_scandesc(int desc, cli_ctx *ctx, cli_file_t ftype, uint8_t ftonly, struc
399 399
     if(groot) {
400 400
 	if(ret != CL_VIRUS) for(i = 0; i < groot->ac_lsigs; i++) {
401 401
 	    evalcnt = 0;
402
-	    if(cli_ac_chklsig(groot->ac_lsigtable[i]->logic, groot->ac_lsigtable[i]->logic + strlen(groot->ac_lsigtable[i]->logic), gdata.lsigcnt[i], &evalcnt, 0) == 1) {
402
+	    evalids = 0;
403
+	    if(cli_ac_chklsig(groot->ac_lsigtable[i]->logic, groot->ac_lsigtable[i]->logic + strlen(groot->ac_lsigtable[i]->logic), gdata.lsigcnt[i], &evalcnt, &evalids, 0) == 1) {
403 404
 		if(ctx->virname)
404 405
 		    *ctx->virname = groot->ac_lsigtable[i]->virname;
405 406
 		ret = CL_VIRUS;
... ...
@@ -899,7 +899,7 @@ static int cli_loadldb(FILE *fs, struct cl_engine **engine, unsigned int *signo,
899 899
 	    break;
900 900
 	}
901 901
 
902
-	subsigs = cli_ac_chklsig(logic, logic + strlen(logic), NULL, NULL, 1);
902
+	subsigs = cli_ac_chklsig(logic, logic + strlen(logic), NULL, NULL, NULL, 1);
903 903
 	if(subsigs == -1) {
904 904
 	    ret = CL_EMALFDB;
905 905
 	    break;