Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
openSUSE:Step:15-SP1
clamav.13051
clamav-zipbomb.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File clamav-zipbomb.patch of Package clamav.13051
--- libclamav/unzip.c.orig +++ libclamav/unzip.c @@ -54,6 +54,8 @@ #define UNZIP_PRIVATE #include "unzip.h" +#define ZIP_MAX_NUM_OVERLAPPING_FILES 5 + #define ZIP_CRC32(r,c,b,l) \ do { \ r = crc32(~c,b,l); \ @@ -500,7 +502,7 @@ static inline int zdecrypt(const uint8_t return CL_SUCCESS; } -static unsigned int lhdr(fmap_t *map, uint32_t loff,uint32_t zsize, unsigned int *fu, unsigned int fc, const uint8_t *ch, int *ret, cli_ctx *ctx, char *tmpd, int detect_encrypted, zip_cb zcb) { +static unsigned int lhdr(fmap_t *map, uint32_t loff,uint32_t zsize, unsigned int *fu, unsigned int fc, const uint8_t *ch, int *ret, cli_ctx *ctx, char *tmpd, int detect_encrypted, zip_cb zcb, uint32_t *file_local_header_size, uint32_t* file_local_data_size) { const uint8_t *lh, *zip; char name[256]; uint32_t csize, usize; @@ -581,6 +583,11 @@ static unsigned int lhdr(fmap_t *map, ui zip+=LH_elen; zsize-=LH_elen; + if (NULL != file_local_header_size) + *file_local_header_size = zip - lh; + if (NULL != file_local_data_size) + *file_local_data_size = csize; + if (!csize) { /* FIXME: what's used for method0 files? csize or usize? Nothing in the specs, needs testing */ cli_dbgmsg("cli_unzip: lh - skipping empty file\n"); } else { @@ -624,12 +631,19 @@ static unsigned int lhdr(fmap_t *map, ui return zip-lh; } -static unsigned int chdr(fmap_t *map, uint32_t coff, uint32_t zsize, unsigned int *fu, unsigned int fc, int *ret, cli_ctx *ctx, char *tmpd, struct zip_requests *requests) { +static unsigned int chdr(fmap_t *map, uint32_t coff, uint32_t zsize, unsigned int *fu, unsigned int fc, int *ret, cli_ctx *ctx, char *tmpd, struct zip_requests *requests, uint32_t *file_local_offset, uint32_t *file_local_header_size, uint32_t *file_local_data_size) { char name[256]; int last = 0; const uint8_t *ch; int virus_found = 0; + if (NULL != file_local_offset) + *file_local_offset = 0; + if (NULL != file_local_header_size) + *file_local_header_size = 0; + if (NULL != file_local_data_size) + *file_local_data_size = 0; + if(!(ch = fmap_need_off(map, coff, SIZEOF_CH)) || CH_magic != 0x02014b50) { if(ch) fmap_unneed_ptr(map, ch, SIZEOF_CH); cli_dbgmsg("cli_unzip: ch - wrkcomplete\n"); @@ -674,7 +688,9 @@ static unsigned int chdr(fmap_t *map, ui if (!requests) { if(CH_off<zsize-SIZEOF_LH) { - lhdr(map, CH_off, zsize-CH_off, fu, fc, ch, ret, ctx, tmpd, 1, zip_scan_cb); + if (NULL != file_local_offset) + *file_local_offset = CH_off; + lhdr(map, CH_off, zsize-CH_off, fu, fc ,ch, ret, ctx, tmpd, 1, zip_scan_cb, file_local_header_size, file_local_data_size); } else cli_dbgmsg("cli_unzip: ch - local hdr out of file\n"); } else { @@ -712,6 +728,13 @@ int cli_unzip(cli_ctx *ctx) { #if HAVE_JSON int toval = 0; #endif + int bZipBombDetected = 0; + uint32_t cur_file_local_offset = 0; + uint32_t cur_file_local_header_size = 0; + uint32_t cur_file_local_data_size = 0; + uint32_t prev_file_local_offset = 0; + uint32_t prev_file_local_header_size = 0; + uint32_t prev_file_local_data_size = 0; cli_dbgmsg("in cli_unzip\n"); fsize = (uint32_t)map->len; @@ -744,20 +767,47 @@ int cli_unzip(cli_ctx *ctx) { } if(coff) { + uint32_t nOverlappingFiles = 0; + cli_dbgmsg("cli_unzip: central @%x\n", coff); - while((coff=chdr(map, coff, fsize, &fu, fc+1, &ret, ctx, tmpd, NULL))) { + while((coff=chdr(map, coff, fsize, &fu, fc+1, &ret, ctx, tmpd, NULL, &cur_file_local_offset, &cur_file_local_header_size, &cur_file_local_data_size))) { fc++; if (ctx->engine->maxfiles && fu>=ctx->engine->maxfiles) { cli_dbgmsg("cli_unzip: Files limit reached (max: %u)\n", ctx->engine->maxfiles); ret=CL_EMAXFILES; } + /* + * Detect overlapping files and zip bombs. + */ + if ((((cur_file_local_offset > prev_file_local_offset) && (cur_file_local_offset < prev_file_local_offset + prev_file_local_header_size + prev_file_local_data_size)) || + ((prev_file_local_offset > cur_file_local_offset) && (prev_file_local_offset < cur_file_local_offset + cur_file_local_header_size + cur_file_local_data_size))) && + (cur_file_local_header_size + cur_file_local_data_size > 0)) { + /* Overlapping file detected */ + nOverlappingFiles++; + + cli_dbgmsg("clip_unzip: Overlapping files detected.\n"); + cli_dbgmsg(" previous file end: %u\n", prev_file_local_offset + prev_file_local_header_size + prev_file_local_data_size); + cli_dbgmsg(" current file start: %u\n", cur_file_local_offset); + if (ZIP_MAX_NUM_OVERLAPPING_FILES < nOverlappingFiles) { + if (SCAN_ALGO) { + ret = cli_append_virus(ctx, "Heuristics.Zip.OverlappingFiles"); + virus_found = 1; + } else { + ret = CL_EFORMAT; + } + bZipBombDetected = 1; + } + } + prev_file_local_offset = cur_file_local_offset; + prev_file_local_header_size = cur_file_local_header_size; + prev_file_local_data_size = cur_file_local_data_size; #if HAVE_JSON if (cli_json_timeout_cycle_check(ctx, &toval) != CL_SUCCESS) { ret=CL_ETIMEOUT; } #endif if (ret != CL_CLEAN) { - if (ret == CL_VIRUS && SCAN_ALL) { + if (ret == CL_VIRUS && SCAN_ALL && !bZipBombDetected) { ret = CL_CLEAN; virus_found = 1; } else @@ -769,7 +819,7 @@ int cli_unzip(cli_ctx *ctx) { ret = CL_VIRUS; if(fu<=(fc/4)) { /* FIXME: make up a sane ratio or remove the whole logic */ fc = 0; - while (ret==CL_CLEAN && lhoff<fsize && (coff=lhdr(map, lhoff, fsize-lhoff, &fu, fc+1, NULL, &ret, ctx, tmpd, 1, zip_scan_cb))) { + while (ret==CL_CLEAN && lhoff<fsize && (coff=lhdr(map, lhoff, fsize-lhoff, &fu, fc+1, NULL, &ret, ctx, tmpd, 1, zip_scan_cb, NULL, NULL))) { fc++; lhoff+=coff; if (SCAN_ALL && ret == CL_VIRUS) { @@ -816,7 +866,7 @@ int unzip_single_internal(cli_ctx *ctx, return CL_CLEAN; } - lhdr(map, lhoffl, fsize, &fu, 0, NULL, &ret, ctx, NULL, 0, zcb); + lhdr(map, lhoffl, fsize, &fu, 0, NULL, &ret, ctx, NULL, 0, zcb, NULL, NULL); return ret; } @@ -886,7 +936,7 @@ int unzip_search(cli_ctx *ctx, fmap_t *m if(coff) { cli_dbgmsg("unzip_search: central @%x\n", coff); - while(ret==CL_CLEAN && (coff=chdr(zmap, coff, fsize, NULL, fc+1, &ret, ctx, NULL, requests))) { + while(ret==CL_CLEAN && (coff=chdr(zmap, coff, fsize, NULL, fc+1, &ret, ctx, NULL, requests, NULL, NULL, NULL))) { if (requests->match) { ret=CL_VIRUS; }
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor