diff --git a/src/encode/lzh.c b/src/encode/lzh.c index ae75736cfd2254acb5f93c1d32f3c5bc3c8d2ec3..c55c4cb9939942c546709378f04908e9802c6b5c 100644 --- a/src/encode/lzh.c +++ b/src/encode/lzh.c @@ -56,6 +56,7 @@ typedef struct { uint16_t getbuf; /* Was just "unsigned" fixed 04/12/95 */ uint8_t text_buf[LZH_STRBUF_SZ]; uint8_t getlen; + size_t outsz; } lzh_decode_t; @@ -70,6 +71,7 @@ typedef struct { uint16_t match_length; uint8_t text_buf[LZH_STRBUF_SZ + LZH_LOOKAHD_SZ - 1]; uint8_t putlen; + size_t outsz; } lzh_encode_t; @@ -319,12 +321,16 @@ static uint8_t lzh_getbyte(lzh_decode_t* lzh, const uint8_t *inbuf, uint32_t *in /* output c bits */ -static void lzh_putcode(lzh_encode_t* lzh, uint16_t l, uint16_t c, uint8_t *outbuf, uint32_t *outlen) +static bool lzh_putcode(lzh_encode_t* lzh, uint16_t l, uint16_t c, uint8_t *outbuf, uint32_t *outlen) { lzh->putbuf |= c >> lzh->putlen; if ((lzh->putlen += l) >= 8) { + if (*outlen >= lzh->outsz || *outlen == UINT32_MAX) + return false; outbuf[(*outlen)++]=(lzh->putbuf >> 8); if ((lzh->putlen -= 8) >= 8) { + if (*outlen >= lzh->outsz || *outlen == UINT32_MAX) + return false; outbuf[(*outlen)++]=lzh->putbuf; lzh->putlen -= 8; lzh->putbuf = c << (l - lzh->putlen); @@ -332,6 +338,7 @@ static void lzh_putcode(lzh_encode_t* lzh, uint16_t l, uint16_t c, uint8_t *outb lzh->putbuf <<= 8; } } + return true; } @@ -460,7 +467,7 @@ static void lzh_update(huffman_t* huff, uint16_t c) } while (((c = huff->parent[c]) != 0) && c < ((sizeof(huff->child)/sizeof(huff->child[0]))-1)); /* do it until reaching the root */ } -static void lzh_encode_char(lzh_encode_t* lzh, uint16_t c, uint8_t *outbuf, uint32_t *outlen) +static bool lzh_encode_char(lzh_encode_t* lzh, uint16_t c, uint8_t *outbuf, uint32_t *outlen) { uint16_t k; uint16_t j; @@ -483,27 +490,33 @@ static void lzh_encode_char(lzh_encode_t* lzh, uint16_t c, uint8_t *outbuf, uint j++; } while ((k = lzh->huff.parent[k]) != LZH_ROOT); - lzh_putcode(lzh, j, i, outbuf, outlen); + if (!lzh_putcode(lzh, j, i, outbuf, outlen)) + return false; lzh_update(&lzh->huff,c); + return true; } -static void lzh_encode_position(lzh_encode_t* lzh, uint16_t c, uint8_t *outbuf, uint32_t *outlen) +static bool lzh_encode_position(lzh_encode_t* lzh, uint16_t c, uint8_t *outbuf, uint32_t *outlen) { unsigned i; /* output upper 6 bits with encoding */ i = c >> 6; - lzh_putcode(lzh, lzh_p_len[i], (lzh_p_code[i] << 8), outbuf, outlen); + if (!lzh_putcode(lzh, lzh_p_len[i], (lzh_p_code[i] << 8), outbuf, outlen)) + return false; /* output lower 6 bits directly */ - lzh_putcode(lzh, 6, (c & 0x3f) << 10, outbuf, outlen); + return lzh_putcode(lzh, 6, (c & 0x3f) << 10, outbuf, outlen); } -static void lzh_encode_end(lzh_encode_t* lzh, uint8_t *outbuf, uint32_t *outlen) +static bool lzh_encode_end(lzh_encode_t* lzh, uint8_t *outbuf, uint32_t *outlen) { if (lzh->putlen) { + if (*outlen >= lzh->outsz || *outlen == UINT32_MAX) + return false; outbuf[(*outlen)++]=(lzh->putbuf >> 8); } + return true; } static uint16_t lzh_decode_char(lzh_decode_t* lzh, const uint8_t *inbuf, uint32_t *incnt, uint32_t inlen) @@ -550,20 +563,21 @@ static uint16_t lzh_decode_position(lzh_decode_t* lzh, const uint8_t *inbuf, uin /* Encoding/Compressing */ /* Returns length of outbuf */ -int32_t lzh_encode(const uint8_t *inbuf, uint32_t inlen, uint8_t *outbuf) +uint32_t lzh_encode(const uint8_t *inbuf, uint32_t inlen, uint8_t *outbuf, size_t outsz) { uint16_t i, c, len, r, s, last_match_length; uint32_t incnt,outlen; lzh_encode_t lzh; memset(&lzh,0,sizeof(lzh)); + lzh.outsz = outsz; incnt=0; inlen = LE_INT32(inlen); memcpy(outbuf,&inlen,sizeof(inlen)); inlen = LE_INT32(inlen); outlen=sizeof(inlen); - if(!inlen) { - return(outlen); } + if(!inlen) + return(0); lzh_start_huff(&lzh.huff); lzh_init_tree(&lzh); s = 0; @@ -581,12 +595,13 @@ int32_t lzh_encode(const uint8_t *inbuf, uint32_t inlen, uint8_t *outbuf) lzh.match_length = len; if (lzh.match_length <= LZH_THRESHOLD) { lzh.match_length = 1; - lzh_encode_char(&lzh,lzh.text_buf[r],outbuf,&outlen); + if (!lzh_encode_char(&lzh,lzh.text_buf[r],outbuf,&outlen)) + return 0; } else { - lzh_encode_char(&lzh,(255 - LZH_THRESHOLD + lzh.match_length) - ,outbuf,&outlen); - lzh_encode_position(&lzh,lzh.match_position - ,outbuf,&outlen); + if (!lzh_encode_char(&lzh,(255 - LZH_THRESHOLD + lzh.match_length) ,outbuf,&outlen)) + return 0; + if (!lzh_encode_position(&lzh,lzh.match_position,outbuf,&outlen)) + return 0; } last_match_length = lzh.match_length; for (i = 0; i < last_match_length && incnt<inlen; i++) { @@ -606,7 +621,8 @@ int32_t lzh_encode(const uint8_t *inbuf, uint32_t inlen, uint8_t *outbuf) if (--len) lzh_insert_node(&lzh,r); } } while (len > 0); - lzh_encode_end(&lzh,outbuf,&outlen); + if (!lzh_encode_end(&lzh,outbuf,&outlen)) + return 0; /* printf("input: %" PRId32 " bytes\n", inlen); printf("output: %" PRId32 " bytes\n", outlen); @@ -618,7 +634,7 @@ int32_t lzh_encode(const uint8_t *inbuf, uint32_t inlen, uint8_t *outbuf) /* Decoding/Uncompressing */ /* Returns length of outbuf */ -int32_t lzh_decode(const uint8_t *inbuf, uint32_t inlen, uint8_t *outbuf) +uint32_t lzh_decode(const uint8_t *inbuf, uint32_t inlen, uint8_t *outbuf, size_t outlen) { uint16_t i, j, k, r, c; uint32_t count; @@ -628,13 +644,16 @@ int32_t lzh_decode(const uint8_t *inbuf, uint32_t inlen, uint8_t *outbuf) lzh_decode_t lzh; memset(&lzh,0,sizeof(lzh)); + lzh.outsz = outlen; incnt=0; memcpy(&textsize,inbuf,sizeof(textsize)); textsize = LE_INT32(textsize); + if (textsize > outlen) + return 0; incnt+=sizeof(textsize); - if (textsize == 0) { - return(textsize); } + if (textsize == 0) + return(textsize); lzh_start_huff(&lzh.huff); for (i = 0; i < LZH_STRBUF_SZ - LZH_LOOKAHD_SZ; i++) *(lzh.text_buf+i) = ' '; @@ -642,6 +661,8 @@ int32_t lzh_decode(const uint8_t *inbuf, uint32_t inlen, uint8_t *outbuf) for (count = 0; count < textsize; ) { c = lzh_decode_char(&lzh,inbuf,&incnt,inlen); if (c < 256) { + if (count >= outlen || count == UINT32_MAX) + return 0; outbuf[count]=(uint8_t)c; #if 0 if(r>(LZH_STRBUF_SZ + LZH_LOOKAHD_SZ - 1) || r<0) { @@ -659,6 +680,8 @@ int32_t lzh_decode(const uint8_t *inbuf, uint32_t inlen, uint8_t *outbuf) j = c - 255 + LZH_THRESHOLD; for (k = 0; k < j && count<textsize; k++) { c = lzh.text_buf[(i + k) & (LZH_STRBUF_SZ - 1)]; + if (count >= outlen || count == UINT32_MAX) + return 0; outbuf[count]=(uint8_t)c; #if 0 if(r>(LZH_STRBUF_SZ + LZH_LOOKAHD_SZ - 1) || r<0) { @@ -676,7 +699,7 @@ int32_t lzh_decode(const uint8_t *inbuf, uint32_t inlen, uint8_t *outbuf) printf("%12ld\n", count); ***/ -return(count); + return(count); } #ifdef LZH_TEST @@ -18239,7 +18262,7 @@ int main(void) { uint32_t lzh_len; - lzh_len = lzh_encode(plaintext, strlen((char*)plaintext), tmp); + lzh_len = lzh_encode(plaintext, strlen((char*)plaintext), tmp, sizeof(tmp)); printf("Compressed Len: %" PRId32 "\n", lzh_len); if (lzh_len != sizeof(compressed)) printf(" Expected Len: %zu\n", sizeof(compressed)); @@ -18247,7 +18270,7 @@ int main(void) if (memcmp(tmp, compressed, lzh_len)) printf(" Bytes different\n"); - lzh_len = lzh_decode(compressed, sizeof(compressed), tmp); + lzh_len = lzh_decode(compressed, sizeof(compressed), tmp, sizeof(tmp)); printf("Uncompressed Size: %" PRId32 "\n", lzh_len); if (lzh_len != strlen((char*)plaintext)) printf(" Expected Len: %zu\n", strlen((char*)plaintext)); @@ -18255,7 +18278,7 @@ int main(void) if (memcmp(tmp, plaintext, lzh_len)) printf(" Bytes different\n"); - lzh_len = lzh_encode(plaintext2, sizeof(plaintext2), tmp); + lzh_len = lzh_encode(plaintext2, sizeof(plaintext2), tmp, sizeof(tmp)); printf("Compressed Len: %" PRId32 "\n", lzh_len); if (lzh_len != sizeof(compressed2)) printf(" Expected Len: %zu\n", sizeof(compressed2)); @@ -18263,7 +18286,7 @@ int main(void) if (memcmp(tmp, compressed2, lzh_len)) printf(" Bytes different\n"); - lzh_len = lzh_decode(compressed2, sizeof(compressed2), tmp); + lzh_len = lzh_decode(compressed2, sizeof(compressed2), tmp, sizeof(tmp)); printf("Uncompressed Size: %" PRId32 "\n", lzh_len); if (lzh_len != sizeof(plaintext2)) printf(" Expected Len: %zu\n", sizeof(plaintext2)); @@ -18271,7 +18294,7 @@ int main(void) if (memcmp(tmp, plaintext2, lzh_len)) printf(" Bytes different\n"); - lzh_len = lzh_encode(ooii_snd_cackle, sizeof(ooii_snd_cackle), tmp); + lzh_len = lzh_encode(ooii_snd_cackle, sizeof(ooii_snd_cackle), tmp, sizeof(tmp)); printf("Compressed Len: %" PRId32 "\n", lzh_len); if (lzh_len != sizeof(ooii_snd_cackle_compressed)) printf(" Expected Len: %zu\n", sizeof(ooii_snd_cackle_compressed)); @@ -18279,7 +18302,7 @@ int main(void) if (memcmp(tmp, ooii_snd_cackle_compressed, lzh_len)) printf(" Bytes different\n"); - lzh_len = lzh_decode(ooii_snd_cackle_compressed, sizeof(ooii_snd_cackle_compressed), tmp); + lzh_len = lzh_decode(ooii_snd_cackle_compressed, sizeof(ooii_snd_cackle_compressed), tmp, sizeof(tmp)); printf("Uncompressed Size: %" PRId32 "\n", lzh_len); if (lzh_len != sizeof(ooii_snd_cackle)) printf(" Expected Len: %zu\n", sizeof(ooii_snd_cackle)); diff --git a/src/encode/lzh.h b/src/encode/lzh.h index 369df7159f884026e053a06b12134c22b31703dd..5cdfeade5efe2d26fb953f4918909ef2b19139bb 100644 --- a/src/encode/lzh.h +++ b/src/encode/lzh.h @@ -41,8 +41,8 @@ #ifdef __cplusplus extern "C" { #endif -LZHEXPORT int32_t lzh_encode(const uint8_t *inbuf, uint32_t inlen, uint8_t *outbuf); -LZHEXPORT int32_t lzh_decode(const uint8_t *inbuf, uint32_t inlen, uint8_t *outbuf); +LZHEXPORT uint32_t lzh_encode(const uint8_t *inbuf, uint32_t inlen, uint8_t *outbuf, size_t outlen); +LZHEXPORT uint32_t lzh_decode(const uint8_t *inbuf, uint32_t inlen, uint8_t *outbuf, size_t outlen); #ifdef __cplusplus } #endif diff --git a/src/smblib/smbadd.c b/src/smblib/smbadd.c index 3b0a038c49f6531d3da258838ad0ee153ca19d72..d5fdd12dace39be86fd739156bdafdd3f4beebce 100644 --- a/src/smblib/smbadd.c +++ b/src/smblib/smbadd.c @@ -34,7 +34,7 @@ int smb_addmsg(smb_t* smb, smbmsg_t* msg, int storage, int dupechk_hashes ,uint16_t xlat, const uchar* body, const uchar* tail) { uchar* lzhbuf=NULL; - int lzhlen; + uint32_t lzhlen; int retval; size_t n; off_t l; @@ -113,7 +113,7 @@ int smb_addmsg(smb_t* smb, smbmsg_t* msg, int storage, int dupechk_hashes /* LZH compress? */ if(xlat==XLAT_LZH && bodylen+taillen>=SDT_BLOCK_LEN && (lzhbuf=(uchar *)malloc(bodylen*2))!=NULL) { - lzhlen=lzh_encode((uchar*)body,bodylen-sizeof(xlat),lzhbuf); + lzhlen=lzh_encode((uchar*)body,bodylen-sizeof(xlat),lzhbuf,bodylen*2); if(lzhlen>1 && smb_datblocks(lzhlen+(sizeof(xlat)*2)+taillen) < smb_datblocks(bodylen+taillen)) { diff --git a/src/smblib/smbtxt.c b/src/smblib/smbtxt.c index 2c313f27ed59398cf451305c48e63c9522b21d2b..a03ba7fce0d35ff32130ac3bf3f3dbd977d324f8 100644 --- a/src/smblib/smbtxt.c +++ b/src/smblib/smbtxt.c @@ -23,6 +23,9 @@ #include <stdlib.h> /* malloc/realloc/free */ #include <string.h> /* strlen */ +/* XPDev */ +#include "xpendian.h" + /* SMB-specific */ #include "smblib.h" #include "base64.h" @@ -38,7 +41,9 @@ char* smb_getmsgtxt(smb_t* smb, smbmsg_t* msg, uint mode) uint16_t xlat; uint i; int lzh; /* bool */ - int l=0,lzhlen,length; + uint32_t lzhlen; + uint32_t lzh_decoded; + int l=0,length; if((buf=(char*)malloc(sizeof(char)))==NULL) { safe_snprintf(smb->last_error, sizeof(smb->last_error) @@ -146,7 +151,8 @@ char* smb_getmsgtxt(smb_t* smb, smbmsg_t* msg, uint mode) free(preamble); return(NULL); } - lzhlen=*(int32_t*)lzhbuf; + memcpy(&lzhlen, lzhbuf, sizeof(lzhlen)); + lzhlen = LE_INT32(lzhlen); if((p=(char*)realloc(buf,l+lzhlen+3L))==NULL) { safe_snprintf(smb->last_error, sizeof(smb->last_error) ,"%s realloc failure of %d bytes for text buffer" @@ -157,7 +163,16 @@ char* smb_getmsgtxt(smb_t* smb, smbmsg_t* msg, uint mode) return(NULL); } buf=p; - lzh_decode((uint8_t *)lzhbuf,length,(uint8_t *)buf+l); + lzh_decoded = lzh_decode((uint8_t *)lzhbuf,length,(uint8_t *)buf+l,l+lzhlen+3); + if (lzh_decoded < lzhlen) { + safe_snprintf(smb->last_error, sizeof(smb->last_error) + ,"%s lzh_decode failure got %" PRIu32 " of %" PRIu32 " bytes for text buffer" + , __FUNCTION__, lzh_decoded, lzhlen); + free(lzhbuf); + free(buf); + free(preamble); + return(NULL); + } free(lzhbuf); l+=lzhlen; }