From 2dbcf7004ae4a8686e9c587d65eee1a8bc8b36e5 Mon Sep 17 00:00:00 2001 From: Tomasz Kojm Date: Sun, 28 Jan 2007 20:22:16 +0000 Subject: [PATCH] improve handling of RAR archives git-svn: trunk@2648 --- clamav-devel/ChangeLog | 4 ++ clamav-devel/libclamav/scanners.c | 28 ++++++++-- clamav-devel/libclamav/unrar/unrar.c | 79 +++++++++++++++------------- clamav-devel/libclamav/unrar/unrar.h | 2 + 4 files changed, 72 insertions(+), 41 deletions(-) diff --git a/clamav-devel/ChangeLog b/clamav-devel/ChangeLog index d43259178..8e906f947 100644 --- a/clamav-devel/ChangeLog +++ b/clamav-devel/ChangeLog @@ -1,3 +1,7 @@ +Sun Jan 28 21:20:05 CET 2007 (tk) +--------------------------------- + * libclamav: improve handling of RAR archives, thanks to Edwin + Sat Jan 27 13:54:35 CET 2007 (acab) ----------------------------------- * libclamav/pe.c: fix debug message logic, fixed handling of non aligned raw diff --git a/clamav-devel/libclamav/scanners.c b/clamav-devel/libclamav/scanners.c index 6f5644cb3..a80f32ee8 100644 --- a/clamav-devel/libclamav/scanners.c +++ b/clamav-devel/libclamav/scanners.c @@ -192,12 +192,20 @@ static int cli_unrar_scanmetadata(int desc, rar_metadata_t *metadata, cli_ctx *c continue; } */ + return ret; +} + +static int cli_unrar_checklimits(const cli_ctx *ctx, const rar_metadata_t *metadata, unsigned int files) +{ if(ctx->limits) { if(ctx->limits->maxratio && metadata->unpack_size && metadata->pack_size) { if((unsigned int) metadata->unpack_size / (unsigned int) metadata->pack_size >= ctx->limits->maxratio) { cli_dbgmsg("RAR: Max ratio reached (normal: %u, compressed: %u, max: %ld)\n", metadata->unpack_size, metadata->pack_size, ctx->limits->maxratio); - *ctx->virname = "Oversized.RAR"; - return CL_VIRUS; + if(BLOCKMAX) { + *ctx->virname = "Oversized.RAR"; + return CL_VIRUS; + } + return CL_EMAXSIZE; } } @@ -207,7 +215,7 @@ static int cli_unrar_scanmetadata(int desc, rar_metadata_t *metadata, cli_ctx *c *ctx->virname = "RAR.ExceededFileSize"; return CL_VIRUS; } - return CL_SUCCESS; + return CL_EMAXSIZE; } if(ctx->limits->maxfiles && (files > ctx->limits->maxfiles)) { @@ -216,11 +224,11 @@ static int cli_unrar_scanmetadata(int desc, rar_metadata_t *metadata, cli_ctx *c *ctx->virname = "RAR.ExceededFilesLimit"; return CL_VIRUS; } - return CL_BREAK; + return CL_EMAXFILES; } } - return ret; + return CL_SUCCESS; } static int cli_scanrar(int desc, cli_ctx *ctx, off_t sfx_offset, uint32_t *sfx_check) @@ -255,6 +263,16 @@ static int cli_scanrar(int desc, cli_ctx *ctx, off_t sfx_offset, uint32_t *sfx_c do { int rc; rar_state.unpack_data->ofd = -1; + ret = cli_unrar_extract_next_prepare(&rar_state,dir); + if(ret != CL_SUCCESS) + break; + ret = cli_unrar_checklimits(ctx, rar_state.metadata_tail, rar_state.file_count); + if(ret && ret != CL_VIRUS) { + ret = CL_CLEAN; + continue; + } else if(ret == CL_VIRUS) { + break; + } ret = cli_unrar_extract_next(&rar_state,dir); if(rar_state.unpack_data->ofd > 0) { lseek(rar_state.unpack_data->ofd,0,SEEK_SET); diff --git a/clamav-devel/libclamav/unrar/unrar.c b/clamav-devel/libclamav/unrar/unrar.c index fb19818a8..7947a7ba3 100644 --- a/clamav-devel/libclamav/unrar/unrar.c +++ b/clamav-devel/libclamav/unrar/unrar.c @@ -1527,26 +1527,25 @@ int cli_unrar_open(int fd, const char *dirname, rar_state_t* state) return CL_SUCCESS; } -int cli_unrar_extract_next(rar_state_t* state,const char* dirname) +int cli_unrar_extract_next_prepare(rar_state_t* state,const char* dirname) { - int retval; unsigned char filename[1024]; int ofd; rar_metadata_t *new_metadata; - file_header_t *file_header = read_block(state->fd, FILE_HEAD); - if (!file_header) { + state->file_header = read_block(state->fd, FILE_HEAD); + if (!state->file_header) { return CL_BREAK;/* end of archive */ } new_metadata = cli_malloc(sizeof(rar_metadata_t)); if (!new_metadata) { return CL_EMEM; } - new_metadata->pack_size = file_header->pack_size; - new_metadata->unpack_size = file_header->unpack_size; - new_metadata->crc = file_header->file_crc; - new_metadata->method = file_header->method; - new_metadata->filename = strdup(file_header->filename); + new_metadata->pack_size = state->file_header->pack_size; + new_metadata->unpack_size = state->file_header->unpack_size; + new_metadata->crc = state->file_header->file_crc; + new_metadata->method = state->file_header->method; + new_metadata->filename = strdup(state->file_header->filename); new_metadata->next = NULL; new_metadata->encrypted = FALSE; if (state->metadata_tail == NULL) { @@ -1555,7 +1554,7 @@ int cli_unrar_extract_next(rar_state_t* state,const char* dirname) state->metadata_tail->next = new_metadata; state->metadata_tail = new_metadata; } - if (file_header->flags & LHD_COMMENT) { + if (state->file_header->flags & LHD_COMMENT) { comment_header_t *comment_header; cli_dbgmsg("File comment present\n"); @@ -1585,54 +1584,62 @@ int cli_unrar_extract_next(rar_state_t* state,const char* dirname) free(comment_header); } } - if (lseek(state->fd, file_header->start_offset+file_header->head_size, SEEK_SET) != - file_header->start_offset+file_header->head_size) { - cli_dbgmsg("Seek failed: %ld\n", state->offset+file_header->head_size); - free(file_header->filename); - free(file_header); + return CL_SUCCESS; +} + +int cli_unrar_extract_next(rar_state_t* state,const char* dirname) +{ + int ofd; + int retval; + + if (lseek(state->fd, state->file_header->start_offset+state->file_header->head_size, SEEK_SET) != + state->file_header->start_offset+state->file_header->head_size) { + cli_dbgmsg("Seek failed: %ld\n", state->offset+state->file_header->head_size); + free(state->file_header->filename); + free(state->file_header); return CL_ERAR; } - if (file_header->flags & LHD_PASSWORD) { - cli_dbgmsg("PASSWORDed file: %s\n", file_header->filename); + if (state->file_header->flags & LHD_PASSWORD) { + cli_dbgmsg("PASSWORDed file: %s\n", state->file_header->filename); state->metadata_tail->encrypted = TRUE; } else /*if (file_header->unpack_size)*/ { snprintf(state->filename, 1024, "%s/%lu.ura", dirname, state->file_count); ofd = open(state->filename, O_RDWR|O_CREAT|O_TRUNC|O_BINARY, 0600); if (ofd < 0) { - free(file_header->filename); - free(file_header); + free(state->file_header->filename); + free(state->file_header); cli_dbgmsg("ERROR: Failed to open output file\n"); return CL_EOPEN; } state->unpack_data->ofd = ofd; - if (file_header->method == 0x30) { + if (state->file_header->method == 0x30) { cli_dbgmsg("Copying stored file (not packed)\n"); - copy_file_data(state->fd, ofd, file_header->pack_size); + copy_file_data(state->fd, ofd, state->file_header->pack_size); } else { - state->unpack_data->dest_unp_size = file_header->unpack_size; - state->unpack_data->pack_size = file_header->pack_size; - if (file_header->unpack_ver <= 15) { + state->unpack_data->dest_unp_size = state->file_header->unpack_size; + state->unpack_data->pack_size = state->file_header->pack_size; + if (state->file_header->unpack_ver <= 15) { retval = rar_unpack(state->fd, 15, (state->file_count>1) && ((state->main_hdr->flags&MHD_SOLID)!=0), state->unpack_data); } else { - if ((state->file_count == 1) && (file_header->flags & LHD_SOLID)) { + if ((state->file_count == 1) && (state->file_header->flags & LHD_SOLID)) { cli_warnmsg("RAR: First file can't be SOLID.\n"); return CL_ERAR; } else { - retval = rar_unpack(state->fd, file_header->unpack_ver, - file_header->flags & LHD_SOLID, state->unpack_data); + retval = rar_unpack(state->fd, state->file_header->unpack_ver, + state->file_header->flags & LHD_SOLID, state->unpack_data); } } - cli_dbgmsg("Expected File CRC: 0x%x\n", file_header->file_crc); + cli_dbgmsg("Expected File CRC: 0x%x\n", state->file_header->file_crc); cli_dbgmsg("Computed File CRC: 0x%x\n", state->unpack_data->unp_crc^0xffffffff); if (state->unpack_data->unp_crc != 0xffffffff) { - if (file_header->file_crc != (state->unpack_data->unp_crc^0xffffffff)) { + if (state->file_header->file_crc != (state->unpack_data->unp_crc^0xffffffff)) { cli_warnmsg("RAR CRC error. Please report the bug at http://bugs.clamav.net/\n"); } } if (!retval) { cli_dbgmsg("Corrupt file detected\n"); - if (file_header->flags & LHD_SOLID) { + if (state->file_header->flags & LHD_SOLID) { cli_dbgmsg("SOLID archive, can't continue\n"); return CL_ERAR; } @@ -1640,14 +1647,14 @@ int cli_unrar_extract_next(rar_state_t* state,const char* dirname) } } - if (lseek(state->fd, file_header->next_offset, SEEK_SET) != file_header->next_offset) { - cli_dbgmsg("ERROR: seek failed: %ld\n", file_header->next_offset); - free(file_header->filename); - free(file_header); + if (lseek(state->fd, state->file_header->next_offset, SEEK_SET) != state->file_header->next_offset) { + cli_dbgmsg("ERROR: seek failed: %ld\n", state->file_header->next_offset); + free(state->file_header->filename); + free(state->file_header); return CL_ERAR; } - free(file_header->filename); - free(file_header); + free(state->file_header->filename); + free(state->file_header); unpack_free_data(state->unpack_data); state->file_count++; return CL_SUCCESS; diff --git a/clamav-devel/libclamav/unrar/unrar.h b/clamav-devel/libclamav/unrar/unrar.h index 2ab581255..8240d8773 100644 --- a/clamav-devel/libclamav/unrar/unrar.h +++ b/clamav-devel/libclamav/unrar/unrar.h @@ -293,6 +293,7 @@ typedef struct unpack_data_tag } unpack_data_t; typedef struct rar_state_tag { + file_header_t* file_header; rar_metadata_t *metadata; rar_metadata_t *metadata_tail; unpack_data_t *unpack_data; @@ -327,6 +328,7 @@ enum BLOCK_TYPES int cli_unrar_extract_next(rar_state_t* state,const char* dirname); +int cli_unrar_extract_next_prepare(rar_state_t* state,const char* dirname); int cli_unrar_open(int fd, const char *dirname, rar_state_t* state); void cli_unrar_close(rar_state_t* state); unsigned int rar_get_char(int fd, unpack_data_t *unpack_data);