libclamav: check .info files while loading CVD/CLD

0.96
Tomasz Kojm 16 years ago
parent 4780d1bb14
commit ace26bfe08
  1. 4
      ChangeLog
  2. 139
      libclamav/cvd.c
  3. 10
      libclamav/cvd.h
  4. 13
      libclamav/others.h
  5. 108
      libclamav/readdb.c

@ -1,3 +1,7 @@
Wed Jan 20 22:10:12 CET 2010 (tk)
---------------------------------
* libclamav: check .info files while loading CVD/CLD
Tue Jan 19 11:49:12 CET 2010 (acab)
-----------------------------------
* clamdscan/proto.c: don't stop scanning if a file is not found (bb#1760)

@ -1,5 +1,5 @@
/*
* Copyright (C) 2007-2009 Sourcefire, Inc.
* Copyright (C) 2007-2010 Sourcefire, Inc.
*
* Authors: Tomasz Kojm
*
@ -42,6 +42,7 @@
#include "cvd.h"
#include "readdb.h"
#include "default.h"
#include "md5.h"
#define TAR_BLOCKSIZE 512
@ -179,20 +180,21 @@ static int cli_untgz(int fd, const char *destdir)
return 0;
}
static int cli_tgzload(int fd, struct cl_engine *engine, unsigned int *signo, unsigned int options)
static int cli_tgzload(int fd, struct cl_engine *engine, unsigned int *signo, unsigned int options, struct cli_dbio *dbio, struct cli_dbinfo *dbinfo)
{
char osize[13], name[101];
char block[TAR_BLOCKSIZE];
int nread, fdd, ret;
unsigned int type, size, pad, compr = 1;
off_t off;
struct cli_dbio dbio;
struct cli_dbinfo *db;
unsigned char hash[16];
#define CLOSE_DBIO \
if(compr) \
gzclose(dbio.gzs); \
gzclose(dbio->gzs); \
else \
fclose(dbio.fs)
fclose(dbio->fs)
cli_dbgmsg("in cli_tgzload()\n");
@ -211,43 +213,43 @@ static int cli_tgzload(int fd, struct cl_engine *engine, unsigned int *signo, un
}
if(compr) {
if((dbio.gzs = gzdopen(fdd, "rb")) == NULL) {
if((dbio->gzs = gzdopen(fdd, "rb")) == NULL) {
cli_errmsg("cli_tgzload: Can't gzdopen() descriptor %d, errno = %d\n", fdd, errno);
return CL_EOPEN;
}
dbio.fs = NULL;
dbio->fs = NULL;
} else {
if((dbio.fs = fdopen(fdd, "rb")) == NULL) {
if((dbio->fs = fdopen(fdd, "rb")) == NULL) {
cli_errmsg("cli_tgzload: Can't fdopen() descriptor %d, errno = %d\n", fdd, errno);
return CL_EOPEN;
}
dbio.gzs = NULL;
dbio->gzs = NULL;
}
dbio.bufsize = CLI_DEFAULT_DBIO_BUFSIZE;
dbio.buf = cli_malloc(dbio.bufsize);
if(!dbio.buf) {
cli_errmsg("cli_tgzload: Can't allocate memory for dbio.buf\n");
dbio->bufsize = CLI_DEFAULT_DBIO_BUFSIZE;
dbio->buf = cli_malloc(dbio->bufsize);
if(!dbio->buf) {
cli_errmsg("cli_tgzload: Can't allocate memory for dbio->buf\n");
CLOSE_DBIO;
return CL_EMALFDB;
}
dbio.bufpt = NULL;
dbio.usebuf = 1;
dbio.readpt = dbio.buf;
dbio->bufpt = NULL;
dbio->usebuf = 1;
dbio->readpt = dbio->buf;
while(1) {
if(compr)
nread = gzread(dbio.gzs, block, TAR_BLOCKSIZE);
nread = gzread(dbio->gzs, block, TAR_BLOCKSIZE);
else
nread = fread(block, 1, TAR_BLOCKSIZE, dbio.fs);
nread = fread(block, 1, TAR_BLOCKSIZE, dbio->fs);
if(!nread)
break;
if(nread != TAR_BLOCKSIZE) {
cli_errmsg("cli_tgzload: Incomplete block read\n");
free(dbio.buf);
free(dbio->buf);
CLOSE_DBIO;
return CL_EMALFDB;
}
@ -260,7 +262,7 @@ static int cli_tgzload(int fd, struct cl_engine *engine, unsigned int *signo, un
if(strchr(name, '/')) {
cli_errmsg("cli_tgzload: Slash separators are not allowed in CVD\n");
free(dbio.buf);
free(dbio->buf);
CLOSE_DBIO;
return CL_EMALFDB;
}
@ -273,12 +275,12 @@ static int cli_tgzload(int fd, struct cl_engine *engine, unsigned int *signo, un
break;
case '5':
cli_errmsg("cli_tgzload: Directories are not supported in CVD\n");
free(dbio.buf);
free(dbio->buf);
CLOSE_DBIO;
return CL_EMALFDB;
default:
cli_errmsg("cli_tgzload: Unknown type flag '%c'\n", type);
free(dbio.buf);
free(dbio->buf);
CLOSE_DBIO;
return CL_EMALFDB;
}
@ -288,45 +290,72 @@ static int cli_tgzload(int fd, struct cl_engine *engine, unsigned int *signo, un
if((sscanf(osize, "%o", &size)) == 0) {
cli_errmsg("cli_tgzload: Invalid size in header\n");
free(dbio.buf);
free(dbio->buf);
CLOSE_DBIO;
return CL_EMALFDB;
}
dbio.size = size;
dbio.readsize = dbio.size < dbio.bufsize ? dbio.size : dbio.bufsize - 1;
dbio.bufpt = NULL;
dbio.readpt = dbio.buf;
dbio->size = size;
dbio->readsize = dbio->size < dbio->bufsize ? dbio->size : dbio->bufsize - 1;
dbio->bufpt = NULL;
dbio->readpt = dbio->buf;
cli_md5_init(&dbio->md5ctx);
dbio->bread = 0;
/* cli_dbgmsg("cli_tgzload: Loading %s, size: %u\n", name, size); */
if(compr)
off = (off_t) gzseek(dbio.gzs, 0, SEEK_CUR);
off = (off_t) gzseek(dbio->gzs, 0, SEEK_CUR);
else
off = ftell(dbio.fs);
off = ftell(dbio->fs);
if(CLI_DBEXT(name)) {
ret = cli_load(name, engine, signo, options, &dbio);
if((!dbinfo && cli_strbcasestr(name, ".info")) || (dbinfo && CLI_DBEXT(name))) {
ret = cli_load(name, engine, signo, options, dbio);
if(ret) {
cli_errmsg("cli_tgzload: Can't load %s\n", name);
free(dbio.buf);
free(dbio->buf);
CLOSE_DBIO;
return CL_EMALFDB;
}
if(!dbinfo) {
free(dbio->buf);
CLOSE_DBIO;
return CL_SUCCESS;
} else {
db = dbinfo;
while(db && strcmp(db->name, name))
db = db->next;
if(!db) {
cli_errmsg("cli_tgzload: File %s not found in .info\n", name);
free(dbio->buf);
CLOSE_DBIO;
return CL_EMALFDB;
}
if(dbio->bread) {
/* TODO: compare sizes; replace with sha256 */
cli_md5_final(hash, &dbio->md5ctx);
if(memcmp(db->hash, hash, 16)) {
cli_errmsg("cli_tgzload: Invalid checksum for file %s\n", name);
free(dbio->buf);
CLOSE_DBIO;
return CL_EMALFDB;
}
}
}
}
pad = size % TAR_BLOCKSIZE ? (TAR_BLOCKSIZE - (size % TAR_BLOCKSIZE)) : 0;
if(compr) {
if(off == gzseek(dbio.gzs, 0, SEEK_CUR))
gzseek(dbio.gzs, size + pad, SEEK_CUR);
if(off == gzseek(dbio->gzs, 0, SEEK_CUR))
gzseek(dbio->gzs, size + pad, SEEK_CUR);
else if(pad)
gzseek(dbio.gzs, pad, SEEK_CUR);
gzseek(dbio->gzs, pad, SEEK_CUR);
} else {
if(off == ftell(dbio.fs))
fseek(dbio.fs, size + pad, SEEK_CUR);
if(off == ftell(dbio->fs))
fseek(dbio->fs, size + pad, SEEK_CUR);
else if(pad)
fseek(dbio.fs, pad, SEEK_CUR);
fseek(dbio->fs, pad, SEEK_CUR);
}
}
free(dbio.buf);
free(dbio->buf);
CLOSE_DBIO;
return CL_SUCCESS;
}
@ -520,22 +549,22 @@ int cl_cvdverify(const char *file)
return ret;
}
int cli_cvdload(FILE *fs, struct cl_engine *engine, unsigned int *signo, unsigned int daily, unsigned int options, unsigned int cld)
int cli_cvdload(FILE *fs, struct cl_engine *engine, unsigned int *signo, unsigned int options, unsigned int cld, const char *dbname)
{
char *dir;
struct cl_cvd cvd;
int ret;
time_t s_time;
int cfd;
struct cli_dbio dbio;
struct cli_dbinfo *dbinfo = NULL;
cli_dbgmsg("in cli_cvdload()\n");
/* verify */
if((ret = cli_cvdverify(fs, &cvd, cld)))
return ret;
if(cvd.stime && daily) {
if(strstr(dbname, "daily.")) {
time(&s_time);
if(cvd.stime > s_time) {
if(cvd.stime - (unsigned int ) s_time > 3600) {
@ -550,6 +579,8 @@ int cli_cvdload(FILE *fs, struct cl_engine *engine, unsigned int *signo, unsigne
cli_warnmsg("*** Please update it as soon as possible. ***\n");
cli_warnmsg("**************************************************\n");
}
engine->dbversion[0] = cvd.version;
engine->dbversion[1] = cvd.stime;
}
if(cvd.fl > cl_retflevel()) {
@ -570,12 +601,26 @@ int cli_cvdload(FILE *fs, struct cl_engine *engine, unsigned int *signo, unsigne
return CL_ESEEK;
}
if(daily) {
engine->dbversion[0] = cvd.version;
engine->dbversion[1] = cvd.stime;
ret = cli_tgzload(cfd, engine, signo, options | CL_DB_OFFICIAL, &dbio, NULL);
if(ret != CL_SUCCESS)
return ret;
/* TODO: check CVD header */
dbinfo = engine->dbinfo ? engine->dbinfo->next : NULL;
if(!dbinfo)
return CL_EMALFDB;
ret = cli_tgzload(cfd, engine, signo, options | CL_DB_OFFICIAL, &dbio, dbinfo);
while(engine->dbinfo) {
dbinfo = engine->dbinfo;
engine->dbinfo = dbinfo->next;
mpool_free(engine->mempool, dbinfo->name);
mpool_free(engine->mempool, dbinfo->hash);
free(dbinfo->cvd);
mpool_free(engine->mempool, dbinfo);
}
return cli_tgzload(cfd, engine, signo, options | CL_DB_OFFICIAL);
return ret;
}
int cli_cvdunpack(const char *file, const char *dir)

@ -1,5 +1,5 @@
/*
* Copyright (C) 2007-2009 Sourcefire, Inc.
* Copyright (C) 2007-2010 Sourcefire, Inc.
*
* Authors: Tomasz Kojm
*
@ -25,16 +25,18 @@
#include <zlib.h>
#include "clamav.h"
#include "md5.h"
struct cli_dbio {
gzFile *gzs;
FILE *fs;
unsigned int size;
unsigned int size, bread;
char *buf, *bufpt, *readpt;
unsigned int usebuf, bufsize, readsize;
cli_md5_ctx md5ctx; /* TODO: replace with sha256 */
};
int cli_cvdload(FILE *fs, struct cl_engine *engine, unsigned int *signo, unsigned int daily, unsigned int options, unsigned int cld);
int cli_cvdload(FILE *fs, struct cl_engine *engine, unsigned int *signo, unsigned int options, unsigned int cld, const char *dbname);
int cli_cvdunpack(const char *file, const char *dir);
#endif

@ -1,5 +1,5 @@
/*
* Copyright (C) 2007-2008 Sourcefire, Inc.
* Copyright (C) 2007-2010 Sourcefire, Inc.
*
* Authors: Tomasz Kojm
*
@ -160,6 +160,14 @@ struct icon_matcher {
unsigned int icon_counts[3];
};
struct cli_dbinfo {
char *name;
unsigned char *hash;
size_t size;
struct cl_cvd *cvd;
struct cli_dbinfo *next;
};
struct cl_engine {
uint32_t refcount; /* reference counter */
uint32_t sdb;
@ -227,6 +235,9 @@ struct cl_engine {
/* Negative cache storage */
struct CACHE *cache;
/* Database information from .info files */
struct cli_dbinfo *dbinfo;
/* Used for memory pools */
mpool_t *mempool;

@ -1,5 +1,5 @@
/*
* Copyright (C) 2007-2009 Sourcefire, Inc.
* Copyright (C) 2007-2010 Sourcefire, Inc.
*
* Authors: Tomasz Kojm
*
@ -350,6 +350,8 @@ char *cli_dbgets(char *buff, unsigned int size, FILE *fs, struct cli_dbio *dbio)
dbio->readpt[bread] = 0;
dbio->bufpt = dbio->buf;
dbio->size -= bread;
dbio->bread += bread;
cli_md5_update(&dbio->md5ctx, dbio->readpt, bread);
}
nl = strchr(dbio->bufpt, '\n');
if(nl) {
@ -394,9 +396,14 @@ char *cli_dbgets(char *buff, unsigned int size, FILE *fs, struct cli_dbio *dbio)
else
pt = fgets(buff, bs, dbio->fs);
dbio->size -= strlen(buff);
if(!pt)
if(!pt) {
cli_errmsg("cli_dbgets: Preliminary end of data\n");
return pt;
}
bs = strlen(buff);
dbio->size -= bs;
dbio->bread += bs;
cli_md5_update(&dbio->md5ctx, buff, bs);
return pt;
}
}
@ -1494,6 +1501,85 @@ static int cli_loadftm(FILE *fs, struct cl_engine *engine, unsigned int options,
return CL_SUCCESS;
}
#define IGN_INFO_TOKENS 2
static int cli_loadinfo(FILE *fs, struct cl_engine *engine, unsigned int options, struct cli_dbio *dbio)
{
const char *tokens[IGN_INFO_TOKENS + 1];
char buffer[FILEBUFF];
unsigned int line = 0, tokens_count;
struct cli_dbinfo *last = NULL, *new;
int ret = CL_SUCCESS;
while(cli_dbgets(buffer, FILEBUFF, fs, dbio)) {
line++;
if(!strncmp(buffer, "DSIG:", 5))
continue; /* TODO */
cli_chomp(buffer);
if(!strncmp("ClamAV-VDB:", buffer, 11)) {
if(engine->dbinfo) { /* shouldn't be initialized at this point */
cli_errmsg("cli_loadinfo: engine->dbinfo already initialized\n");
ret = CL_EMALFDB;
break;
}
last = engine->dbinfo = (struct cli_dbinfo *) mpool_calloc(engine->mempool, 1, sizeof(struct cli_bm_patt));
if(!engine->dbinfo) {
ret = CL_EMEM;
break;
}
engine->dbinfo->cvd = cl_cvdparse(buffer);
if(!engine->dbinfo->cvd) {
cli_errmsg("cli_loadinfo: Can't parse header entry\n");
ret = CL_EMALFDB;
break;
}
continue;
}
if(!last) {
cli_errmsg("cli_loadinfo: Incorrect file format\n");
ret = CL_EMALFDB;
break;
}
tokens_count = cli_strtokenize(buffer, ':', IGN_INFO_TOKENS + 1, tokens);
if(tokens_count > IGN_INFO_TOKENS) {
ret = CL_EMALFDB;
break;
}
new = (struct cli_dbinfo *) mpool_calloc(engine->mempool, 1, sizeof(struct cli_dbinfo));
if(!new) {
ret = CL_EMEM;
break;
}
new->name = (unsigned char *) cli_mpool_strdup(engine->mempool, tokens[0]);
if(!new->name) {
mpool_free(engine->mempool, new);
ret = CL_EMEM;
break;
}
/* TODO: hash will be replaced with sha256 */
if(strlen(tokens[1]) != 32 || !(new->hash = cli_mpool_hex2str(engine->mempool, tokens[1]))) {
cli_errmsg("cli_loadinfo: Malformed MD5 string at line %u\n", line);
mpool_free(engine->mempool, new->name);
mpool_free(engine->mempool, new);
ret = CL_EMALFDB;
break;
}
new->size = 0; /* TODO */
last->next = new;
last = new;
}
if(ret) {
cli_errmsg("cli_loadinfo: Problem parsing database at line %u\n", line);
return ret;
}
return CL_SUCCESS;
}
#define IGN_MAX_TOKENS 3
static int cli_loadign(FILE *fs, struct cl_engine *engine, unsigned int options, struct cli_dbio *dbio)
{
@ -2083,10 +2169,10 @@ int cli_load(const char *filename, struct cl_engine *engine, unsigned int *signo
ret = cli_loaddb(fs, engine, signo, options, dbio, dbname);
} else if(cli_strbcasestr(dbname, ".cvd")) {
ret = cli_cvdload(fs, engine, signo, !strcmp(dbname, "daily.cvd"), options, 0);
ret = cli_cvdload(fs, engine, signo, options, 0, dbname);
} else if(cli_strbcasestr(dbname, ".cld")) {
ret = cli_cvdload(fs, engine, signo, !strcmp(dbname, "daily.cld"), options, 1);
ret = cli_cvdload(fs, engine, signo, options, 1, dbname);
} else if(cli_strbcasestr(dbname, ".hdb")) {
ret = cli_loadmd5(fs, engine, signo, MD5_HDB, options, dbio, dbname);
@ -2143,6 +2229,9 @@ int cli_load(const char *filename, struct cl_engine *engine, unsigned int *signo
} else if(cli_strbcasestr(dbname, ".cfg")) {
ret = cli_dconf_load(fs, engine, options, dbio);
} else if(cli_strbcasestr(dbname, ".info")) {
ret = cli_loadinfo(fs, engine, options, dbio);
} else if(cli_strbcasestr(dbname, ".wdb")) {
if(options & CL_DB_PHISHING_URLS) {
ret = cli_loadwdb(fs, engine, options, dbio);
@ -2671,6 +2760,15 @@ int cl_engine_free(struct cl_engine *engine)
mpool_free(engine->mempool, pt);
}
while(engine->dbinfo) {
struct cli_dbinfo *pt = engine->dbinfo;
engine->dbinfo = pt->next;
mpool_free(engine->mempool, pt->name);
mpool_free(engine->mempool, pt->hash);
free(pt->cvd);
mpool_free(engine->mempool, pt);
}
if(engine->dconf->bytecode & BYTECODE_ENGINE_MASK) {
if (engine->bcs.all_bcs)
for(i=0;i<engine->bcs.count;i++)

Loading…
Cancel
Save