~ubuntu-branches/ubuntu/raring/clamav/raring

« back to all changes in this revision

Viewing changes to libclamav/matcher-ac.c

  • Committer: Bazaar Package Importer
  • Author(s): Stephen Gran
  • Date: 2008-09-05 17:25:34 UTC
  • mfrom: (0.35.1 lenny)
  • Revision ID: james.westby@ubuntu.com-20080905172534-yi3f8fkye1o7u1r3
* New upstream version (closes: #497662, #497773)
  - lots of new options for clamd.conf
  - fixes CVEs CVE-2008-3912, CVE-2008-3913, CVE-2008-3914, and
    CVE-2008-1389
* No longer supports --unzip option, so typo is gone (closes: #496276)
* Translations:
  - sv (thanks Martin Bagge <brother@bsnet.se>) (closes: #491760)

Show diffs side-by-side

added added

removed removed

Lines of Context:
25
25
#include <stdio.h>
26
26
#include <string.h>
27
27
#include <stdlib.h>
 
28
#include <ctype.h>
28
29
#ifdef  HAVE_UNISTD_H
29
30
#include <unistd.h>
30
31
#endif
36
37
#include "filetypes.h"
37
38
#include "cltypes.h"
38
39
#include "str.h"
 
40
#include "readdb.h"
39
41
 
40
42
uint8_t cli_ac_mindepth = AC_DEFAULT_MIN_DEPTH;
41
43
uint8_t cli_ac_maxdepth = AC_DEFAULT_MAX_DEPTH;
372
374
    }
373
375
}
374
376
 
 
377
/*
 
378
 * In parse_only mode this function returns -1 on error or the max subsig id
 
379
 */
 
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
{
 
382
        unsigned int i, len = end - expr, pth = 0, opoff = 0, op1off = 0, val;
 
383
        unsigned int blkend = 0, id, modval1, modval2 = 0, lcnt = 0, rcnt = 0, tcnt, modoff = 0;
 
384
        uint64_t lids = 0, rids = 0, tids;
 
385
        int ret, lval, rval;
 
386
        char op = 0, op1 = 0, mod = 0, blkmod = 0;
 
387
        const char *lstart = expr, *lend = NULL, *rstart = NULL, *rend = end, *pt;
 
388
 
 
389
 
 
390
    for(i = 0; i < len; i++) {
 
391
        switch(expr[i]) {
 
392
            case '(':
 
393
                pth++;
 
394
                break;
 
395
 
 
396
            case ')':
 
397
                if(!pth) {
 
398
                    cli_errmsg("cli_ac_chklsig: Syntax error: Missing opening parenthesis\n");
 
399
                    return -1;
 
400
                }
 
401
                pth--;
 
402
 
 
403
            case '>':
 
404
            case '<':
 
405
            case '=':
 
406
                mod = expr[i];
 
407
                modoff = i;
 
408
                break;
 
409
 
 
410
            default:
 
411
                if(strchr("&|", expr[i])) {
 
412
                    if(!pth) {
 
413
                        op = expr[i];
 
414
                        opoff = i;
 
415
                    } else if(pth == 1) {
 
416
                        op1 = expr[i];
 
417
                        op1off = i;
 
418
                    }
 
419
                }
 
420
        }
 
421
 
 
422
        if(op)
 
423
            break;
 
424
 
 
425
        if(op1 && !pth) {
 
426
            blkend = i;
 
427
            if(expr[i + 1] == '>' || expr[i + 1] == '<' || expr[i + 1] == '=') {
 
428
                blkmod = expr[i + 1];
 
429
                ret = sscanf(&expr[i + 2], "%u,%u", &modval1, &modval2);
 
430
                if(ret != 2)
 
431
                    ret = sscanf(&expr[i + 2], "%u", &modval1);
 
432
                if(!ret || ret == EOF) {
 
433
                    cli_errmsg("chklexpr: Syntax error: Missing number after '%c'\n", expr[i + 1]);
 
434
                    return -1;
 
435
                }
 
436
                for(i += 2; i + 1 < len && (isdigit(expr[i + 1]) || expr[i + 1] == ','); i++);
 
437
            }
 
438
 
 
439
            if(&expr[i + 1] == rend)
 
440
                break;
 
441
            else
 
442
                blkmod = 0;
 
443
        }
 
444
    }
 
445
 
 
446
    if(pth) {
 
447
        cli_errmsg("cli_ac_chklsig: Syntax error: Missing closing parenthesis\n");
 
448
        return -1;
 
449
    }
 
450
 
 
451
    if(!op && !op1) {
 
452
        if(expr[0] == '(')
 
453
            return cli_ac_chklsig(++expr, --end, lsigcnt, cnt, ids, parse_only);
 
454
 
 
455
        ret = sscanf(expr, "%u", &id);
 
456
        if(!ret || ret == EOF) {
 
457
            cli_errmsg("cli_ac_chklsig: Can't parse %s\n", expr);
 
458
            return -1;
 
459
        }
 
460
 
 
461
        if(parse_only)
 
462
            val = id;
 
463
        else
 
464
            val = lsigcnt[id];
 
465
 
 
466
        if(mod) {
 
467
            pt = strchr(expr, mod) + modoff;
 
468
            ret = sscanf(pt, "%u", &modval1);
 
469
            if(!ret || ret == EOF) {
 
470
                cli_errmsg("chklexpr: Syntax error: Missing number after '%c'\n", mod);
 
471
                return -1;
 
472
            }
 
473
            if(!parse_only) {
 
474
                switch(mod) {
 
475
                    case '=':
 
476
                        if(val != modval1)
 
477
                            return 0;
 
478
                        break;
 
479
                    case '<':
 
480
                        if(val >= modval1)
 
481
                            return 0;
 
482
                        break;
 
483
                    case '>':
 
484
                        if(val <= modval1)
 
485
                            return 0;
 
486
                        break;
 
487
                    default:
 
488
                        return 0;
 
489
                }
 
490
                *cnt += val;
 
491
                *ids |= (uint64_t) 1 << id;
 
492
                return 1;
 
493
            }
 
494
        }
 
495
 
 
496
        if(parse_only) {
 
497
            return val;
 
498
        } else {
 
499
            if(val) {
 
500
                *cnt += val;
 
501
                *ids |= (uint64_t) 1 << id;
 
502
                return 1;
 
503
            } else {
 
504
                return 0;
 
505
            }
 
506
        }
 
507
    }
 
508
 
 
509
    if(!op) {
 
510
        op = op1;
 
511
        opoff = op1off;
 
512
        lstart++;
 
513
        rend = &expr[blkend];
 
514
    }
 
515
 
 
516
    if(!opoff) {
 
517
        cli_errmsg("cli_ac_chklsig: Syntax error: Missing left argument\n");
 
518
        return -1;
 
519
    }
 
520
    lend = &expr[opoff];
 
521
    if(opoff + 1 == len) {
 
522
        cli_errmsg("cli_ac_chklsig: Syntax error: Missing right argument\n");
 
523
        return -1;
 
524
    }
 
525
    rstart = &expr[opoff + 1];
 
526
 
 
527
    lval = cli_ac_chklsig(lstart, lend, lsigcnt, &lcnt, &lids, parse_only);
 
528
    if(lval == -1) {
 
529
        cli_errmsg("cli_ac_chklsig: Calculation of lval failed\n");
 
530
        return -1;
 
531
    }
 
532
 
 
533
    rval = cli_ac_chklsig(rstart, rend, lsigcnt, &rcnt, &rids, parse_only);
 
534
    if(rval == -1) {
 
535
        cli_errmsg("cli_ac_chklsig: Calculation of rval failed\n");
 
536
        return -1;
 
537
    }
 
538
 
 
539
    if(parse_only) {
 
540
        switch(op) {
 
541
            case '&':
 
542
            case '|':
 
543
                return MAX(lval, rval);
 
544
            default:
 
545
                cli_errmsg("cli_ac_chklsig: Incorrect operator type\n");
 
546
                return -1;
 
547
        }
 
548
    } else {
 
549
        switch(op) {
 
550
            case '&':
 
551
                ret = lval && rval;
 
552
                break;
 
553
            case '|':
 
554
                ret = lval || rval;
 
555
                break;
 
556
            default:
 
557
                cli_errmsg("cli_ac_chklsig: Incorrect operator type\n");
 
558
                return -1;
 
559
        }
 
560
 
 
561
        if(!blkmod) {
 
562
            if(ret) {
 
563
                *cnt += lcnt + rcnt;
 
564
                *ids |= lids | rids;
 
565
            }
 
566
            return ret;
 
567
        } else {
 
568
            if(ret) {
 
569
                tcnt = lcnt + rcnt;
 
570
                tids = lids | rids;
 
571
            } else {
 
572
                tcnt = 0;
 
573
                tids = 0;
 
574
            }
 
575
 
 
576
            switch(blkmod) {
 
577
                case '=':
 
578
                    if(tcnt != modval1)
 
579
                        return 0;
 
580
                    break;
 
581
                case '<':
 
582
                    if(tcnt >= modval1)
 
583
                        return 0;
 
584
                    break;
 
585
                case '>':
 
586
                    if(tcnt <= modval1)
 
587
                        return 0;
 
588
                    break;
 
589
                default:
 
590
                    return 0;
 
591
            }
 
592
 
 
593
            if(modval2) {
 
594
                val = 0;
 
595
                while(tids) {
 
596
                    val += tids & (uint64_t) 1;
 
597
                    tids >>= 1;
 
598
                }
 
599
                if(val < modval2)
 
600
                    return 0;
 
601
            }
 
602
            *cnt += tcnt;
 
603
            return 1;
 
604
        }
 
605
    }
 
606
}
 
607
 
375
608
/* 
376
609
 * FIXME: the current support for string alternatives uses a brute-force
377
610
 *        approach and doesn't perform any kind of verification and
480
713
 
481
714
    if(!(pattern->ch[0] & CLI_MATCH_IGNORE)) {
482
715
        bp = offset - pattern->prefix_length;
483
 
        if(pattern->ch_mindist[0] + 1 > bp)
 
716
        if(pattern->ch_mindist[0] + (uint32_t) 1 > bp)
484
717
            return 0;
485
718
        bp -= pattern->ch_mindist[0] + 1;
486
719
        for(i = pattern->ch_mindist[0]; i <= pattern->ch_maxdist[0]; i++) {
500
733
    return 1;
501
734
}
502
735
 
503
 
int cli_ac_initdata(struct cli_ac_data *data, uint32_t partsigs, uint8_t tracklen)
 
736
int cli_ac_initdata(struct cli_ac_data *data, uint32_t partsigs, uint32_t lsigs, uint8_t tracklen)
504
737
{
 
738
        unsigned int i;
 
739
 
505
740
 
506
741
    if(!data) {
507
742
        cli_errmsg("cli_ac_init: data == NULL\n");
510
745
 
511
746
    data->partsigs = partsigs;
512
747
 
513
 
    if(!partsigs)
514
 
        return CL_SUCCESS;
515
 
 
516
 
    data->offmatrix = (int32_t ***) cli_calloc(partsigs, sizeof(int32_t **));
517
 
    if(!data->offmatrix) {
518
 
        cli_errmsg("cli_ac_init: Can't allocate memory for data->offmatrix\n");
519
 
        return CL_EMEM;
 
748
    if(partsigs) {
 
749
        data->offmatrix = (int32_t ***) cli_calloc(partsigs, sizeof(int32_t **));
 
750
        if(!data->offmatrix) {
 
751
            cli_errmsg("cli_ac_init: Can't allocate memory for data->offmatrix\n");
 
752
            return CL_EMEM;
 
753
        }
520
754
    }
521
 
 
 
755
 
 
756
    data->lsigs = lsigs;
 
757
    if(lsigs) {
 
758
        data->lsigcnt = (uint32_t **) cli_malloc(lsigs * sizeof(uint32_t *));
 
759
        if(!data->lsigcnt) {
 
760
            if(partsigs)
 
761
                free(data->offmatrix);
 
762
            cli_errmsg("cli_ac_init: Can't allocate memory for data->lsigcnt\n");
 
763
            return CL_EMEM;
 
764
        }
 
765
        data->lsigcnt[0] = (uint32_t *) cli_calloc(lsigs * 64, sizeof(uint32_t));
 
766
        if(!data->lsigcnt[0]) {
 
767
            free(data->lsigcnt);
 
768
            if(partsigs)
 
769
                free(data->offmatrix);
 
770
            cli_errmsg("cli_ac_init: Can't allocate memory for data->lsigcnt[0]\n");
 
771
            return CL_EMEM;
 
772
        }
 
773
        for(i = 1; i < lsigs; i++)
 
774
            data->lsigcnt[i] = data->lsigcnt[0] + 64 * i;
 
775
     }
 
776
 
522
777
    return CL_SUCCESS;
523
778
}
524
779
 
535
790
            }
536
791
        }
537
792
        free(data->offmatrix);
 
793
        data->partsigs = 0;
 
794
    }
 
795
 
 
796
    if(data && data->lsigs) {
 
797
        free(data->lsigcnt[0]);
 
798
        free(data->lsigcnt);
 
799
        data->lsigs = 0;
538
800
    }
539
801
}
540
802
 
570
832
    return CL_SUCCESS;
571
833
}
572
834
 
573
 
int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **virname, 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)
 
835
int cli_ac_scanbuff(const unsigned char *buffer, uint32_t length, const char **virname, void **customdata, struct cli_ac_result **res, 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)
574
836
{
575
837
        struct cli_ac_node *current;
576
838
        struct cli_ac_patt *patt, *pt;
580
842
        uint8_t found;
581
843
        struct cli_target_info info;
582
844
        int type = CL_CLEAN;
 
845
        struct cli_ac_result *newres;
583
846
 
584
847
 
585
848
    if(!root->ac_root)
615
878
 
616
879
                        realoff = offset + bp - pt->prefix_length;
617
880
 
618
 
                        if((pt->offset || pt->target) && (!pt->sigid || pt->partno == 1)) {
 
881
                        if(pt->offset && (!pt->sigid || pt->partno == 1)) {
619
882
                            if((fd == -1 && !ftype) || !cli_validatesig(ftype, pt->offset, realoff, &info, fd, pt->virname)) {
620
883
                                pt = pt->next_same;
621
884
                                continue;
633
896
                                mdata->offmatrix[pt->sigid - 1] = cli_malloc(pt->parts * sizeof(int32_t *));
634
897
                                if(!mdata->offmatrix[pt->sigid - 1]) {
635
898
                                    cli_errmsg("cli_ac_scanbuff: Can't allocate memory for mdata->offmatrix[%u]\n", pt->sigid - 1);
 
899
                                    if(info.exeinfo.section)
 
900
                                        free(info.exeinfo.section);
636
901
                                    return CL_EMEM;
637
902
                                }
638
903
 
641
906
                                    cli_errmsg("cli_ac_scanbuff: Can't allocate memory for mdata->offmatrix[%u][0]\n", pt->sigid - 1);
642
907
                                    free(mdata->offmatrix[pt->sigid - 1]);
643
908
                                    mdata->offmatrix[pt->sigid - 1] = NULL;
 
909
                                    if(info.exeinfo.section)
 
910
                                        free(info.exeinfo.section);
644
911
                                    return CL_EMEM;
645
912
                                }
646
913
                                memset(mdata->offmatrix[pt->sigid - 1][0], -1, pt->parts * (AC_DEFAULT_TRACKLEN + 1) * sizeof(int32_t));
706
973
                                    }
707
974
 
708
975
                                } else { /* !pt->type */
709
 
                                    if(virname)
710
 
                                        *virname = pt->virname;
711
 
 
712
 
                                    if(info.exeinfo.section)
713
 
                                        free(info.exeinfo.section);
714
 
 
715
 
                                    return CL_VIRUS;
 
976
                                    if(pt->lsigid[0]) {
 
977
                                        mdata->lsigcnt[pt->lsigid[1]][pt->lsigid[2]]++;
 
978
                                        pt = pt->next;
 
979
                                        continue;
 
980
                                    }
 
981
 
 
982
                                    if(res) {
 
983
                                        newres = (struct cli_ac_result *) malloc(sizeof(struct cli_ac_result));
 
984
                                        if(!newres) {
 
985
                                            if(info.exeinfo.section)
 
986
                                                free(info.exeinfo.section);
 
987
                                            return CL_EMEM;
 
988
                                        }
 
989
                                        newres->virname = pt->virname;
 
990
                                        newres->customdata = pt->customdata;
 
991
                                        newres->next = *res;
 
992
                                        *res = newres;
 
993
 
 
994
                                        pt = pt->next;
 
995
                                        continue;
 
996
                                    } else {
 
997
                                        if(virname)
 
998
                                            *virname = pt->virname;
 
999
                                        if(customdata)
 
1000
                                            *customdata = pt->customdata;
 
1001
 
 
1002
                                        if(info.exeinfo.section)
 
1003
                                            free(info.exeinfo.section);
 
1004
 
 
1005
                                        return CL_VIRUS;
 
1006
                                    }
716
1007
                                }
717
1008
                            }
718
1009
 
737
1028
                                    }
738
1029
                                }
739
1030
                            } else {
740
 
                                if(virname)
741
 
                                    *virname = pt->virname;
742
 
 
743
 
                                if(info.exeinfo.section)
744
 
                                    free(info.exeinfo.section);
745
 
                                return CL_VIRUS;
 
1031
                                if(pt->lsigid[0]) {
 
1032
                                    mdata->lsigcnt[pt->lsigid[1]][pt->lsigid[2]]++;
 
1033
                                    pt = pt->next;
 
1034
                                    continue;
 
1035
                                }
 
1036
 
 
1037
                                if(res) {
 
1038
                                    newres = (struct cli_ac_result *) malloc(sizeof(struct cli_ac_result));
 
1039
                                    if(!newres) {
 
1040
                                        if(info.exeinfo.section)
 
1041
                                            free(info.exeinfo.section);
 
1042
                                        return CL_EMEM;
 
1043
                                    }
 
1044
                                    newres->virname = pt->virname;
 
1045
                                    newres->customdata = pt->customdata;
 
1046
                                    newres->next = *res;
 
1047
                                    *res = newres;
 
1048
 
 
1049
                                    pt = pt->next;
 
1050
                                    continue;
 
1051
                                } else {
 
1052
                                    if(virname)
 
1053
                                        *virname = pt->virname;
 
1054
                                    if(customdata)
 
1055
                                        *customdata = pt->customdata;
 
1056
 
 
1057
                                    if(info.exeinfo.section)
 
1058
                                        free(info.exeinfo.section);
 
1059
 
 
1060
                                    return CL_VIRUS;
 
1061
                                }
746
1062
                            }
747
1063
                        }
748
1064
                        pt = pt->next_same;
760
1076
}
761
1077
 
762
1078
/* FIXME: clean up the code */
763
 
int cli_ac_addsig(struct cli_matcher *root, const char *virname, const char *hexsig, uint32_t sigid, uint16_t parts, uint16_t partno, uint16_t rtype, uint16_t type, uint32_t mindist, uint32_t maxdist, const char *offset, uint8_t target)
 
1079
int cli_ac_addsig(struct cli_matcher *root, const char *virname, const char *hexsig, uint32_t sigid, uint16_t parts, uint16_t partno, uint16_t rtype, uint16_t type, uint32_t mindist, uint32_t maxdist, const char *offset, const uint32_t *lsigid, unsigned int options)
764
1080
{
765
1081
        struct cli_ac_patt *new;
766
1082
        char *pt, *pt2, *hex = NULL, *hexcpy = NULL;
767
1083
        uint16_t i, j, ppos = 0, pend, *dec;
768
 
        uint8_t wprefix = 0, zprefix = 1, namelen, plen = 0;
 
1084
        uint8_t wprefix = 0, zprefix = 1, plen = 0;
769
1085
        struct cli_ac_alt *newalt, *altpt, **newtable;
770
1086
        int ret, error = CL_SUCCESS;
771
1087
 
772
1088
 
 
1089
    if(!root) {
 
1090
        cli_errmsg("cli_ac_addsig: root == NULL\n");
 
1091
        return CL_ENULLARG;
 
1092
    }
 
1093
 
773
1094
    if(strlen(hexsig) / 2 < root->ac_mindepth)
774
1095
        return CL_EPATSHORT;
775
1096
 
783
1104
    new->partno = partno;
784
1105
    new->mindist = mindist;
785
1106
    new->maxdist = maxdist;
786
 
    new->target = target;
 
1107
    new->customdata = NULL;
787
1108
    new->ch[0] |= CLI_MATCH_IGNORE;
788
1109
    new->ch[1] |= CLI_MATCH_IGNORE;
 
1110
    if(lsigid) {
 
1111
        new->lsigid[0] = 1;
 
1112
        memcpy(&new->lsigid[1], lsigid, 2 * sizeof(uint32_t));
 
1113
    }
789
1114
 
790
1115
    if(strchr(hexsig, '[')) {
791
1116
        if(!(hexcpy = cli_strdup(hexsig))) {
1059
1384
    if(new->length > root->maxpatlen)
1060
1385
        root->maxpatlen = new->length;
1061
1386
 
1062
 
    if((pt = strstr(virname, " (Clam)")))
1063
 
        namelen = strlen(virname) - strlen(pt);
1064
 
    else
1065
 
        namelen = strlen(virname);
1066
 
 
1067
 
    if(!namelen) {
1068
 
        cli_errmsg("cli_ac_addsig: No virus name\n");
1069
 
        new->prefix ? free(new->prefix) : free(new->pattern);
1070
 
        ac_free_alt(new);
1071
 
        free(new);
1072
 
        return CL_EMALFDB;
1073
 
    }
1074
 
 
1075
 
    if((new->virname = cli_calloc(namelen + 1, sizeof(char))) == NULL) {
 
1387
    new->virname = cli_virname((char *) virname, options & CL_DB_OFFICIAL, 0);
 
1388
    if(!new->virname) {
1076
1389
        new->prefix ? free(new->prefix) : free(new->pattern);
1077
1390
        ac_free_alt(new);
1078
1391
        free(new);
1079
1392
        return CL_EMEM;
1080
1393
    }
1081
 
    strncpy(new->virname, virname, namelen);
1082
 
    new->virname[namelen]='\0';
 
1394
 
 
1395
    if(new->lsigid[0])
 
1396
        root->ac_lsigtable[new->lsigid[1]]->virname = new->virname;
1083
1397
 
1084
1398
    if(offset) {
1085
1399
        new->offset = cli_strdup(offset);