Browse code

add MD5 based false positive eliminator

git-svn-id: file:///var/lib/svn/clamav-devel/trunk/clamav-devel@1380 77e5149b-7576-45b1-b177-96237e5ba77b

Tomasz Kojm authored on 2005/03/07 08:40:57
Showing 8 changed files
... ...
@@ -1,3 +1,7 @@
1
+Mon Mar  7 00:37:34 CET 2005 (tk)
2
+---------------------------------
3
+  * libclamav: add MD5 based false positive eliminator
4
+
1 5
 Mon Mar  7 00:32:38 CET 2005 (tk)
2 6
 ---------------------------------
3 7
   * configure: add support for QNX 6 (patch by mikep*kaluga.org)
... ...
@@ -117,6 +117,7 @@ struct cli_md5_node {
117 117
     char *virname, *viralias;
118 118
     unsigned char *md5;
119 119
     unsigned int size;
120
+    unsigned short fp;
120 121
     struct cli_md5_node *next;
121 122
 };
122 123
 
... ...
@@ -148,6 +148,40 @@ static long int cli_caloff(const char *offstr, int fd)
148 148
     return -1;
149 149
 }
150 150
 
151
+int cli_checkfp(int fd, const struct cl_node *root)
152
+{
153
+	struct cli_md5_node *md5_node;
154
+	char *digest;
155
+
156
+
157
+    if(root->md5_hlist) {
158
+
159
+	if(!(digest = cli_md5digest(fd))) {
160
+	    cli_errmsg("cli_checkfp(): Can't generate MD5 checksum\n");
161
+	    return 0;
162
+	}
163
+
164
+	if((md5_node = cli_vermd5(digest, root)) && md5_node->fp) {
165
+		struct stat sb;
166
+
167
+	    if(fstat(fd, &sb))
168
+		return CL_EIO;
169
+
170
+	    if(sb.st_size != md5_node->size) {
171
+		cli_warnmsg("Detected false positive MD5 match. Please report.\n");
172
+	    } else {
173
+		cli_dbgmsg("Eliminated false positive match (fp sig: %s)\n", md5_node->virname);
174
+		free(digest);
175
+		return 1;
176
+	    }
177
+	}
178
+
179
+	free(digest);
180
+    }
181
+
182
+    return 0;
183
+}
184
+
151 185
 int cli_validatesig(unsigned short target, unsigned short ftype, const char *offstr, unsigned long int fileoff, int desc, const char *virname)
152 186
 {
153 187
 
... ...
@@ -258,7 +292,12 @@ int cli_scandesc(int desc, const char **virname, long int *scanned, const struct
258 258
 	    free(buffer);
259 259
 	    free(partcnt);
260 260
 	    free(partoff);
261
-	    return CL_VIRUS;
261
+
262
+	    lseek(desc, 0, SEEK_SET);
263
+	    if(cli_checkfp(desc, root))
264
+		return CL_CLEAN;
265
+	    else
266
+		return CL_VIRUS;
262 267
 
263 268
 	} else if(otfrec && ret >= CL_TYPENO) {
264 269
 	    if(ret >= type)
... ...
@@ -297,7 +336,7 @@ int cli_scandesc(int desc, const char **virname, long int *scanned, const struct
297 297
 	    cli_dbgmsg("Calculated MD5 checksum: %s\n", md5str);
298 298
 	}
299 299
 
300
-	if((md5_node = cli_vermd5(digest, root))) {
300
+	if((md5_node = cli_vermd5(digest, root)) && !md5_node->fp) {
301 301
 		struct stat sb;
302 302
 
303 303
 	    if(fstat(desc, &sb))
... ...
@@ -27,4 +27,6 @@ int cli_scanbuff(const char *buffer, unsigned int length, const char **virname,
27 27
 
28 28
 int cli_validatesig(unsigned short target, unsigned short ftype, const char *offstr, unsigned long int fileoff, int desc, const char *virname);
29 29
 
30
+int cli_checkfp(int fd, const struct cl_node *root);
31
+
30 32
 #endif
... ...
@@ -192,6 +192,27 @@ const char *cl_perror(int clerror)
192 192
     return cl_strerror(clerror);
193 193
 }
194 194
 
195
+unsigned char *cli_md5digest(int desc)
196
+{
197
+	unsigned char *digest;
198
+	char buff[FILEBUFF];
199
+	MD5_CTX ctx;
200
+	int bytes;
201
+
202
+
203
+    if(!(digest = cli_malloc(16)))
204
+	return NULL;
205
+
206
+    MD5_Init(&ctx);
207
+
208
+    while((bytes = cli_readn(desc, buff, FILEBUFF)))
209
+	MD5_Update(&ctx, buff, bytes);
210
+
211
+    MD5_Final(digest, &ctx);
212
+
213
+    return digest;
214
+}
215
+
195 216
 char *cli_md5stream(FILE *fs, unsigned char *digcpy)
196 217
 {
197 218
 	unsigned char digest[16];
... ...
@@ -30,6 +30,7 @@ void *cli_malloc(size_t nmemb);
30 30
 void *cli_calloc(size_t nmemb, size_t size);
31 31
 void *cli_realloc(void *ptr, size_t size);
32 32
 int cli_rmdirs(const char *dirname);
33
+unsigned char *cli_md5digest(int desc);
33 34
 char *cli_md5stream(FILE *fs, unsigned char *digcpy);
34 35
 char *cli_md5file(const char *filename);
35 36
 int cli_readn(int fd, void *buff, unsigned int count);
... ...
@@ -612,7 +612,7 @@ static int cli_loadndb(FILE *fd, struct cl_node **root, unsigned int *signo)
612 612
     return 0;
613 613
 }
614 614
 
615
-static int cli_loadhdb(FILE *fd, struct cl_node **root, unsigned int *signo)
615
+static int cli_loadhdb(FILE *fd, struct cl_node **root, unsigned int *signo, unsigned short fp)
616 616
 {
617 617
 	char buffer[FILEBUFF], *pt;
618 618
 	int line = 0, ret = 0;
... ...
@@ -636,6 +636,8 @@ static int cli_loadhdb(FILE *fd, struct cl_node **root, unsigned int *signo)
636 636
 	    break;
637 637
 	}
638 638
 
639
+	new->fp = fp;
640
+
639 641
 	if(!(pt = cli_strtok(buffer, 0, ":"))) {
640 642
 	    free(new);
641 643
 	    ret = CL_EMALFDB;
... ...
@@ -893,7 +895,10 @@ int cl_loaddb(const char *filename, struct cl_node **root, unsigned int *signo)
893 893
 	ret = cli_cvdload(fd, root, signo, warn);
894 894
 
895 895
     } else if(cli_strbcasestr(filename, ".hdb")) {
896
-	ret = cli_loadhdb(fd, root, signo);
896
+	ret = cli_loadhdb(fd, root, signo, 0);
897
+
898
+    } else if(cli_strbcasestr(filename, ".fp")) {
899
+	ret = cli_loadhdb(fd, root, signo, 1);
897 900
 
898 901
     } else if(cli_strbcasestr(filename, ".ndb")) {
899 902
 	ret = cli_loadndb(fd, root, signo);
... ...
@@ -950,6 +955,7 @@ int cl_loaddbdir(const char *dirname, struct cl_node **root, unsigned int *signo
950 950
 	     cli_strbcasestr(dent->d_name, ".db2")  ||
951 951
 	     cli_strbcasestr(dent->d_name, ".db3")  ||
952 952
 	     cli_strbcasestr(dent->d_name, ".hdb")  ||
953
+	     cli_strbcasestr(dent->d_name, ".fp")  ||
953 954
 	     cli_strbcasestr(dent->d_name, ".ndb")  ||
954 955
 	     cli_strbcasestr(dent->d_name, ".zmd")  ||
955 956
 	     cli_strbcasestr(dent->d_name, ".cvd"))) {
... ...
@@ -1028,6 +1034,7 @@ int cl_statinidir(const char *dirname, struct cl_stat *dbstat)
1028 1028
 	    cli_strbcasestr(dent->d_name, ".db2")  || 
1029 1029
 	    cli_strbcasestr(dent->d_name, ".db3")  || 
1030 1030
 	    cli_strbcasestr(dent->d_name, ".hdb")  || 
1031
+	    cli_strbcasestr(dent->d_name, ".fp")  || 
1031 1032
 	    cli_strbcasestr(dent->d_name, ".ndb")  || 
1032 1033
 	    cli_strbcasestr(dent->d_name, ".zmd")  || 
1033 1034
 	    cli_strbcasestr(dent->d_name, ".cvd"))) {
... ...
@@ -1097,6 +1104,7 @@ int cl_statchkdir(const struct cl_stat *dbstat)
1097 1097
 	    cli_strbcasestr(dent->d_name, ".db2")  || 
1098 1098
 	    cli_strbcasestr(dent->d_name, ".db3")  || 
1099 1099
 	    cli_strbcasestr(dent->d_name, ".hdb")  || 
1100
+	    cli_strbcasestr(dent->d_name, ".fp")  || 
1100 1101
 	    cli_strbcasestr(dent->d_name, ".ndb")  || 
1101 1102
 	    cli_strbcasestr(dent->d_name, ".zmd")  || 
1102 1103
 	    cli_strbcasestr(dent->d_name, ".cvd"))) {
... ...
@@ -288,7 +288,7 @@ int build(struct optstruct *opt)
288 288
 	    exit(1);
289 289
 	case 0:
290 290
 	    {
291
-		char *args[] = { "tar", "-cvf", NULL, "COPYING", "main.db", "daily.db", "Notes", "viruses.db3", "main.hdb", "daily.hdb", "main.ndb", "daily.ndb", "main.zmd", "daily.zmd", NULL };
291
+		char *args[] = { "tar", "-cvf", NULL, "COPYING", "main.db", "daily.db", "Notes", "viruses.db3", "main.hdb", "daily.hdb", "main.ndb", "daily.ndb", "main.zmd", "daily.zmd", "main.fp", "daily.fp", NULL };
292 292
 		args[2] = tarfile;
293 293
 		execv("/bin/tar", args);
294 294
 		mprintf("!Can't execute tar\n");