comparison src/lzfu.c @ 41:183ae993b9ad

security fix for potential buffer overrun in lz decompress
author carl
date Tue, 02 Oct 2007 15:49:44 -0700
parents ddfb25318812
children f6db1f060a95
comparison
equal deleted inserted replaced
40:be6d5329cc01 41:183ae993b9ad
13 #include "libpst.h" 13 #include "libpst.h"
14 #include <sys/types.h> 14 #include <sys/types.h>
15 #include <string.h> 15 #include <string.h>
16 #include <stdio.h> 16 #include <stdio.h>
17 17
18 #ifndef _MSC_VER
19 #include <stdint.h>
20 #endif
21
22 #ifdef _MSC_VER
23 #define uint32_t unsigned int
24 #endif
25
26 #include "lzfu.h" 18 #include "lzfu.h"
27 19
28 #define LZFU_COMPRESSED 0x75465a4c 20 #define LZFU_COMPRESSED 0x75465a4c
29 #define LZFU_UNCOMPRESSED 0x414c454d 21 #define LZFU_UNCOMPRESSED 0x414c454d
30 22
31 // initital dictionary 23 // initital dictionary
32 #define LZFU_INITDICT "{\\rtf1\\ansi\\mac\\deff0\\deftab720{\\fonttbl;}" \ 24 #define LZFU_INITDICT "{\\rtf1\\ansi\\mac\\deff0\\deftab720{\\fonttbl;}" \
33 "{\\f0\\fnil \\froman \\fswiss \\fmodern \\fscrip" \ 25 "{\\f0\\fnil \\froman \\fswiss \\fmodern \\fscrip" \
34 "t \\fdecor MS Sans SerifSymbolArialTimes Ne" \ 26 "t \\fdecor MS Sans SerifSymbolArialTimes Ne" \
35 "w RomanCourier{\\colortbl\\red0\\green0\\blue0" \ 27 "w RomanCourier{\\colortbl\\red0\\green0\\blue0" \
36 "\r\n\\par \\pard\\plain\\f0\\fs20\\b\\i\\u\\tab" \ 28 "\r\n\\par \\pard\\plain\\f0\\fs20\\b\\i\\u\\tab" \
37 "\\tx" 29 "\\tx"
38 // initial length of dictionary 30 // initial length of dictionary
39 #define LZFU_INITLENGTH 207 31 #define LZFU_INITLENGTH 207
40 32
41 // header for compressed rtf 33 // header for compressed rtf
42 typedef struct _lzfuheader { 34 typedef struct _lzfuheader {
43 uint32_t cbSize; 35 u_int32_t cbSize;
44 uint32_t cbRawSize; 36 u_int32_t cbRawSize;
45 uint32_t dwMagic; 37 u_int32_t dwMagic;
46 uint32_t dwCRC; 38 u_int32_t dwCRC;
47 } lzfuheader; 39 } lzfuheader;
48 40
49 41
50 /** 42 unsigned char* lzfu_decompress (unsigned char* rtfcomp, u_int32_t compsize, size_t *size) {
51 We always need to add 0x10 to the buffer offset because we need to skip past the header info
52 */
53
54 unsigned char* lzfu_decompress (unsigned char* rtfcomp, size_t *size) {
55 // the dictionary buffer 43 // the dictionary buffer
56 unsigned char dict[4096]; 44 unsigned char dict[4096];
57 // the dictionary pointer 45 // the dictionary pointer
58 unsigned int dict_length=0; 46 unsigned int dict_length=0;
59 // the header of the lzfu block 47 // the header of the lzfu block
60 lzfuheader lzfuhdr; 48 lzfuheader lzfuhdr;
61 // container for the data blocks 49 // container for the data blocks
62 unsigned char flags; 50 unsigned char flags;
63 // temp value for determining the bits in the flag 51 // temp value for determining the bits in the flag
64 unsigned char flag_mask; 52 unsigned char flag_mask;
65 unsigned int i, in_size; 53 u_int32_t i;
66 unsigned char *out_buf; 54 unsigned char *out_buf;
67 unsigned int out_ptr = 0; 55 u_int32_t out_ptr = 0;
56 u_int32_t out_size;
57 u_int32_t in_ptr;
58 u_int32_t in_size;
68 59
69 memcpy(dict, LZFU_INITDICT, LZFU_INITLENGTH); 60 memcpy(dict, LZFU_INITDICT, LZFU_INITLENGTH);
70 dict_length = LZFU_INITLENGTH; 61 dict_length = LZFU_INITLENGTH;
71 memcpy(&lzfuhdr, rtfcomp, sizeof(lzfuhdr)); 62 memcpy(&lzfuhdr, rtfcomp, sizeof(lzfuhdr));
72 LE32_CPU(lzfuhdr.cbSize); 63 LE32_CPU(lzfuhdr.cbSize);
73 LE32_CPU(lzfuhdr.cbRawSize); 64 LE32_CPU(lzfuhdr.cbRawSize);
74 LE32_CPU(lzfuhdr.dwMagic); 65 LE32_CPU(lzfuhdr.dwMagic);
75 LE32_CPU(lzfuhdr.dwCRC); 66 LE32_CPU(lzfuhdr.dwCRC);
76 /* printf("total size: %d\n", lzfuhdr.cbSize+4); 67 //printf("total size: %d\n", lzfuhdr.cbSize+4);
77 printf("raw size : %d\n", lzfuhdr.cbRawSize); 68 //printf("raw size : %d\n", lzfuhdr.cbRawSize);
78 printf("compressed: %s\n", (lzfuhdr.dwMagic == LZFU_COMPRESSED ? "yes" : "no")); 69 //printf("compressed: %s\n", (lzfuhdr.dwMagic == LZFU_COMPRESSED ? "yes" : "no"));
79 printf("CRC : %#x\n", lzfuhdr.dwCRC); 70 //printf("CRC : %#x\n", lzfuhdr.dwCRC);
80 printf("\n");*/ 71 //printf("\n");
81 out_buf = (unsigned char*)xmalloc(lzfuhdr.cbRawSize+20); //plus 4 cause we have 2x'}' and a \0 72 out_size = lzfuhdr.cbRawSize + 3; // two braces and a null terminator
82 in_size = 0; 73 out_buf = (unsigned char*)xmalloc(out_size);
83 // we add plus one here cause when referencing an array, the index is always one less 74 in_ptr = sizeof(lzfuhdr);
84 // (ie, when accessing 2 element array, highest index is [1]) 75 in_size = (lzfuhdr.cbSize < compsize) ? lzfuhdr.cbSize : compsize;
85 while (in_size+0x11 < lzfuhdr.cbSize) { 76 while (in_ptr < in_size) {
86 memcpy(&flags, &(rtfcomp[in_size+0x10]), 1); 77 flags = rtfcomp[in_ptr++];
87 in_size += 1;
88
89 flag_mask = 1; 78 flag_mask = 1;
90 while (flag_mask != 0 && in_size+0x11 < lzfuhdr.cbSize) { 79 while (flag_mask) {
91 if (flag_mask & flags) { 80 if (flag_mask & flags) {
92 // read 2 bytes from input 81 // two bytes available?
93 unsigned short int blkhdr, offset, length; 82 if (in_ptr+1 < in_size) {
94 memcpy(&blkhdr, &(rtfcomp[in_size+0x10]), 2); 83 // read 2 bytes from input
95 LE16_CPU(blkhdr); 84 unsigned short int blkhdr, offset, length;
96 in_size += 2; 85 memcpy(&blkhdr, rtfcomp+in_ptr, 2);
97 /* swap the upper and lower bytes of blkhdr */ 86 LE16_CPU(blkhdr);
98 blkhdr = (((blkhdr&0xFF00)>>8)+ 87 in_ptr += 2;
99 ((blkhdr&0x00FF)<<8)); 88 /* swap the upper and lower bytes of blkhdr */
100 /* the offset is the first 24 bits of the 32 bit value */ 89 blkhdr = (((blkhdr&0xFF00)>>8)+
101 offset = (blkhdr&0xFFF0)>>4; 90 ((blkhdr&0x00FF)<<8));
102 /* the length of the dict entry are the last 8 bits */ 91 /* the offset is the first 12 bits of the 16 bit value */
103 length = (blkhdr&0x000F)+2; 92 offset = (blkhdr&0xFFF0)>>4;
104 // add the value we are about to print to the dictionary 93 /* the length of the dict entry are the last 4 bits */
105 for (i=0; i < length; i++) { 94 length = (blkhdr&0x000F)+2;
106 unsigned char c1; 95 // add the value we are about to print to the dictionary
107 c1 = dict[(offset+i)%4096]; 96 for (i=0; i < length; i++) {
108 dict[dict_length]=c1; 97 unsigned char c1;
109 dict_length = (dict_length+1) % 4096; 98 c1 = dict[(offset+i)%4096];
110 out_buf[out_ptr++] = c1; 99 dict[dict_length]=c1;
100 dict_length = (dict_length+1) % 4096;
101 if (out_ptr < out_size) out_buf[out_ptr++] = c1;
102 }
111 } 103 }
112 } else { 104 } else {
113 // uncompressed chunk (single byte) 105 // one byte available?
114 char c1 = rtfcomp[in_size+0x10]; 106 if (in_ptr < in_size) {
115 in_size ++; 107 // uncompressed chunk (single byte)
116 dict[dict_length] = c1; 108 char c1 = rtfcomp[in_ptr++];
117 dict_length = (dict_length+1)%4096; 109 dict[dict_length] = c1;
118 out_buf[out_ptr++] = c1; 110 dict_length = (dict_length+1)%4096;
111 if (out_ptr < out_size) out_buf[out_ptr++] = c1;
112 }
119 } 113 }
120 flag_mask <<= 1; 114 flag_mask <<= 1;
121 } 115 }
122 } 116 }
123 // the compressed version doesn't appear to drop the closing braces onto the doc. 117 // the compressed version doesn't appear to drop the closing
124 // we should do that 118 // braces onto the doc, so we do that here.
125 out_buf[out_ptr++] = '}'; 119 if (out_ptr < out_size) out_buf[out_ptr++] = '}';
126 out_buf[out_ptr++] = '}'; 120 if (out_ptr < out_size) out_buf[out_ptr++] = '}';
127 *size = out_ptr; 121 *size = out_ptr;
128 out_buf[out_ptr++] = '\0'; 122 if (out_ptr < out_size) out_buf[out_ptr++] = '\0';
129 return out_buf; 123 return out_buf;
130 } 124 }