clamav/libclamav/explode.c

321 lines
7.9 KiB
C
Raw Normal View History

/*
* Copyright (C) 2015-2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
* Copyright (C) 2008 Sourcefire, Inc.
*
* Authors: Alberto Wu
*
* Acknowledgements: Written from scratch based on specs from PKWARE:
* http://www.pkware.com/documents/casestudies/APPNOTE.TXT
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
/*
* Written from scratch based on specs from PKWARE:
* see www.pkware.com/documents/casestudies/APPNOTE.TXT
*
* To the best of my knowledge, it's patent free:
* http://www.unisys.com/about__unisys/lzw
*/
Spelling Adjustments (#30) * spelling: accessed * spelling: alignment * spelling: amalgamated * spelling: answers * spelling: another * spelling: acquisition * spelling: apitid * spelling: ascii * spelling: appending * spelling: appropriate * spelling: arbitrary * spelling: architecture * spelling: asynchronous * spelling: attachments * spelling: argument * spelling: authenticode * spelling: because * spelling: boundary * spelling: brackets * spelling: bytecode * spelling: calculation * spelling: cannot * spelling: changes * spelling: check * spelling: children * spelling: codegen * spelling: commands * spelling: container * spelling: concatenated * spelling: conditions * spelling: continuous * spelling: conversions * spelling: corresponding * spelling: corrupted * spelling: coverity * spelling: crafting * spelling: daemon * spelling: definition * spelling: delivered * spelling: delivery * spelling: delimit * spelling: dependencies * spelling: dependency * spelling: detection * spelling: determine * spelling: disconnects * spelling: distributed * spelling: documentation * spelling: downgraded * spelling: downloading * spelling: endianness * spelling: entities * spelling: especially * spelling: empty * spelling: expected * spelling: explicitly * spelling: existent * spelling: finished * spelling: flexibility * spelling: flexible * spelling: freshclam * spelling: functions * spelling: guarantee * spelling: hardened * spelling: headaches * spelling: heighten * spelling: improper * spelling: increment * spelling: indefinitely * spelling: independent * spelling: inaccessible * spelling: infrastructure Conflicts: docs/html/node68.html * spelling: initializing * spelling: inited * spelling: instream * spelling: installed * spelling: initialization * spelling: initialize * spelling: interface * spelling: intrinsics * spelling: interpreter * spelling: introduced * spelling: invalid * spelling: latency * spelling: lawyers * spelling: libclamav * spelling: likelihood * spelling: loop * spelling: maximum * spelling: million * spelling: milliseconds * spelling: minimum * spelling: minzhuan * spelling: multipart * spelling: misled * spelling: modifiers * spelling: notifying * spelling: objects * spelling: occurred * spelling: occurs * spelling: occurrences * spelling: optimization * spelling: original * spelling: originated * spelling: output * spelling: overridden * spelling: parenthesis * spelling: partition * spelling: performance * spelling: permission * spelling: phishing * spelling: portions * spelling: positives * spelling: preceded * spelling: properties * spelling: protocol * spelling: protos * spelling: quarantine * spelling: recursive * spelling: referring * spelling: reorder * spelling: reset * spelling: resources * spelling: resume * spelling: retrieval * spelling: rewrite * spelling: sanity * spelling: scheduled * spelling: search * spelling: section * spelling: separator * spelling: separated * spelling: specify * spelling: special * spelling: statement * spelling: streams * spelling: succession * spelling: suggests * spelling: superfluous * spelling: suspicious * spelling: synonym * spelling: temporarily * spelling: testfiles * spelling: transverse * spelling: turkish * spelling: typos * spelling: unable * spelling: unexpected * spelling: unexpectedly * spelling: unfinished * spelling: unfortunately * spelling: uninitialized * spelling: unlocking * spelling: unnecessary * spelling: unpack * spelling: unrecognized * spelling: unsupported * spelling: usable * spelling: wherever * spelling: wishlist * spelling: white * spelling: infrastructure * spelling: directories * spelling: overridden * spelling: permission * spelling: yesterday * spelling: initialization * spelling: intrinsics * space adjustment for spelling changes * minor modifications by klin
2018-02-21 15:00:59 -05:00
/* To Cami and Dario, the only lawyers I can stand */
#if HAVE_CONFIG_H
#include "clamav-config.h"
#endif
#if HAVE_STRING_H
#include <string.h>
#endif
2014-07-01 19:38:01 -04:00
#include "clamav.h"
#include "explode.h"
#include "others.h"
/* NOTE: sorting algo must be stable! */
static void bs(uint8_t *k, uint8_t *v, unsigned int elements) {
uint8_t tmp;
unsigned int i=0, l=0, stop=0, r=elements;
while(!stop) {
stop=1;
for(; i<r; i++) {
if(v[k[i]]>v[k[i+1]]) {
tmp=k[i];
k[i]=k[i+1];
k[i+1]=tmp;
stop=0;
}
}
if(stop) break;
r--;
i--;
for(; i>l; i--) {
if(v[k[i]]<v[k[i-1]]) {
tmp=k[i];
k[i]=k[i-1];
k[i-1]=tmp;
stop=0;
}
}
l++;
i++;
}
}
static int unpack_tree(struct xplstate *X, uint32_t *tree, unsigned int expected) {
uint8_t temptree[256], order[256], *ttree=temptree;
uint8_t *cur=X->window;
uint8_t packsz;
unsigned int i;
uint16_t code=0, codeinc=0, lastlen=0;
packsz=*cur++;
for(i=0; i<expected; i++) order[i]=i;
i=expected;
do {
uint8_t values, len;
values = *cur++;
len = (values&15) + 1;
values = (values>>4) + 1;
if(values>i) return 1;
i-=values;
while(values--)
*ttree++ = len;
} while(packsz--);
if(i) return 1;
bs(order, temptree, expected-1);
i=expected-1;
do {
code=code+codeinc;
if(temptree[order[i]]!=lastlen) {
lastlen=temptree[order[i]];
codeinc=1<<(16-lastlen);
}
tree[order[i]]=code | ((uint32_t)lastlen<<16);
} while(i--);
return 0;
}
/* bit lame of a lookup, but prolly not worth optimizing */
static int lookup_tree(uint32_t *tree, unsigned int size, uint16_t code, uint8_t len) {
uint32_t lookup=((uint32_t)(len+1))<<16 | code;
unsigned int i;
for(i=0; i<size; i++)
if(tree[i]==lookup) return i;
return -1;
}
2008-01-05 02:43:07 +00:00
int explode_init(struct xplstate *X, uint16_t flags) {
X->bits = X->cur = 0;
if(flags&2) {
X->largewin = 1;
X->mask = 0x1fff;
} else {
X->largewin = 0;
X->mask = 0xfff;
}
if(flags&4) {
X->state = GRABLITS;
X->litcodes = 1;
X->minlen=3;
} else {
X->state = GRABLENS;
X->litcodes = 0;
X->minlen=2;
}
X->got=0;
return EXPLODE_OK;
}
#define GETBIT \
if(X->bits) { \
X->bits--; \
val=X->bitmap&1; \
X->bitmap>>=1; \
} else { \
if(!X->avail_in) return EXPLODE_EBUFF; \
if(X->avail_in>=4) { \
X->bitmap=cli_readint32(X->next_in); \
X->bits=31; \
X->next_in+=4; \
X->avail_in-=4; \
} else { \
X->bitmap=*X->next_in; \
X->bits=7; \
X->next_in++; \
X->avail_in--; \
} \
val=X->bitmap&1; \
X->bitmap>>=1; \
}
#define GETBITS(NUM) \
if(X->bits>=(NUM)) { \
val=X->bitmap&((1<<(NUM))-1); \
X->bitmap>>=(NUM); \
X->bits-=(NUM); \
} else { \
if(X->avail_in*8+X->bits<(NUM)) return EXPLODE_EBUFF; \
val=X->bitmap; \
if(X->avail_in>=4) { \
X->bitmap=cli_readint32(X->next_in); \
X->next_in+=4; \
X->avail_in-=4; \
val|=(X->bitmap&((1<<((NUM)-X->bits))-1))<<X->bits; \
X->bitmap>>=(NUM)-X->bits; \
X->bits=32-((NUM)-X->bits); \
} else { \
X->bitmap=*X->next_in; \
X->next_in++; \
X->avail_in--; \
val|=(X->bitmap&((1<<((NUM)-X->bits))-1))<<X->bits; \
X->bitmap>>=(NUM)-X->bits; \
X->bits=8-((NUM)-X->bits); \
} \
}
#define GETCODES(CASE, WHICH, HOWMANY) \
case CASE: { \
if(!X->avail_in) return EXPLODE_EBUFF; \
if(!X->got) need = *X->next_in; \
else need = X->window[0]; \
if(need > HOWMANY - 1) return EXPLODE_ESTREAM; /* too many codes */ \
need = need + 2 - X->got; /* bytes remaining */ \
if(need>X->avail_in) { /* if not enuff */ \
/* just copy what's avail... */ \
memcpy(&X->window[X->got], X->next_in, X->avail_in); \
X->got += X->avail_in; \
X->next_in += X->avail_in; \
X->avail_in = 0; \
return EXPLODE_EBUFF; /* ...and beg for more */ \
} \
/* else fetch what's needed */ \
memcpy(&X->window[X->got], X->next_in, need); \
X->avail_in -= need; \
X->next_in += need; \
if(unpack_tree(X, X->WHICH, HOWMANY )) return EXPLODE_ESTREAM; \
/* and move on */ \
X->got=0; \
X->state++; \
}
#define SETCASE(CASE) \
X->state = (CASE); \
case(CASE): \
{/* FAKE */}
int explode(struct xplstate *X) {
unsigned int val, need;
int temp=-1;
switch(X->state) {
/* grab compressed coded literals, if present */
GETCODES(GRABLITS, lit_tree, 256);
/* grab compressed coded lens */
GETCODES(GRABLENS, len_tree, 64);
/* grab compressed coded dists */
GETCODES(GRABDISTS, dist_tree, 64);
case EXPLODE:
while(X->avail_in || X->bits) {
GETBIT; /* can't fail */
if(val) {
if(X->litcodes) {
X->backsize=0;
X->state=EXPLODE_LITCODES;
for(X->got=0; X->got<=15; X->got++) {
case EXPLODE_LITCODES:
GETBIT;
X->backsize|=val<<(15-X->got);
if((temp=lookup_tree(X->lit_tree, 256, X->backsize, X->got))!=-1) break;
}
if(temp==-1) return EXPLODE_ESTREAM;
X->got=temp;
} else {
SETCASE(EXPLODE_LITS);
GETBITS(8);
X->got=val;
}
SETCASE(EXPLODE_WBYTE);
if(!X->avail_out) return EXPLODE_EBUFF;
X->avail_out--;
*X->next_out = X->window[X->cur & X->mask] = X->got;
X->cur++;
X->next_out++;
} else {
SETCASE(EXPLODE_BASEDIST);
GETBITS(6u+X->largewin);
X->backbytes=val;
X->backsize=0;
X->state=EXPLODE_DECODEDISTS;
for(X->got=0; X->got<=15; X->got++) {
case EXPLODE_DECODEDISTS:
GETBIT;
X->backsize|=val<<(15-X->got);
if((temp=lookup_tree(X->dist_tree, 64, X->backsize, X->got))!=-1) break;
}
if(temp==-1) return EXPLODE_ESTREAM;
X->backbytes|=temp<<(6+X->largewin);
X->backbytes++;
X->backsize=0;
X->state=EXPLODE_DECODELENS;
for(X->got=0; X->got<=15; X->got++) {
case EXPLODE_DECODELENS:
GETBIT;
X->backsize|=val<<(15-X->got);
if((temp=lookup_tree(X->len_tree, 64, X->backsize, X->got))!=-1) break;
}
if(temp==-1) return EXPLODE_ESTREAM;
if(temp==63) {
SETCASE(EXPLODE_DECODEEXTRA);
GETBITS(8);
temp=63+val;
}
X->backsize=temp+X->minlen;
X->state=EXPLODE_BACKCOPY;
while(X->backsize--) {
case EXPLODE_BACKCOPY:
if(!X->avail_out) return EXPLODE_EBUFF;
X->avail_out--;
if (X->cur>=X->backbytes)
*X->next_out = X->window[X->cur & X->mask] = X->window[(X->cur-X->backbytes) & X->mask];
else
*X->next_out = X->window[X->cur & X->mask] = 0;
X->cur++;
X->next_out++;
}
}
X->state=EXPLODE;
}
}
return EXPLODE_EBUFF;
}
void explode_shutdown(void) {}