system/corennnnn
Revision | a47780b99894478ec68fc246c4c8725c54ac89f6 (tree) |
---|---|
Time | 2016-09-21 17:26:10 |
Author | Narayan Kamath <narayan@goog...> |
Commiter | android-build-merger |
libzipfile: add additional validity checks. am: a1ec23634a
am: c307830f5d
Change-Id: I5d856cec4528541ff5416456cbe1338c78a09699
@@ -60,16 +60,20 @@ read_central_dir_values(Zipfile* file, const unsigned char* buf, int len) | ||
60 | 60 | return 0; |
61 | 61 | } |
62 | 62 | |
63 | +static const int kCompressionStored = 0x0; | |
64 | +static const int kCompressionDeflate = 0x8; | |
65 | + | |
63 | 66 | static int |
64 | 67 | read_central_directory_entry(Zipfile* file, Zipentry* entry, |
65 | 68 | const unsigned char** buf, ssize_t* len) |
66 | 69 | { |
67 | 70 | const unsigned char* p; |
71 | + size_t remaining; | |
72 | + const unsigned char* bufLimit; | |
68 | 73 | |
69 | 74 | unsigned short versionMadeBy; |
70 | 75 | unsigned short versionToExtract; |
71 | 76 | unsigned short gpBitFlag; |
72 | - unsigned short compressionMethod; | |
73 | 77 | unsigned short lastModFileTime; |
74 | 78 | unsigned short lastModFileDate; |
75 | 79 | unsigned long crc32; |
@@ -84,8 +88,9 @@ read_central_directory_entry(Zipfile* file, Zipentry* entry, | ||
84 | 88 | unsigned int dataOffset; |
85 | 89 | unsigned short lfhExtraFieldSize; |
86 | 90 | |
87 | - | |
88 | 91 | p = *buf; |
92 | + remaining = *len; | |
93 | + bufLimit = file->buf + file->bufsize; | |
89 | 94 | |
90 | 95 | if (*len < ENTRY_LEN) { |
91 | 96 | fprintf(stderr, "cde entry not large enough\n"); |
@@ -115,41 +120,88 @@ read_central_directory_entry(Zipfile* file, Zipentry* entry, | ||
115 | 120 | localHeaderRelOffset = read_le_int(&p[0x2a]); |
116 | 121 | |
117 | 122 | p += ENTRY_LEN; |
123 | + remaining -= ENTRY_LEN; | |
118 | 124 | |
119 | 125 | // filename |
120 | 126 | if (entry->fileNameLength != 0) { |
127 | + if (entry->fileNameLength > remaining) { | |
128 | + fprintf(stderr, "cde entry not large enough for file name.\n"); | |
129 | + return 1; | |
130 | + } | |
131 | + | |
121 | 132 | entry->fileName = p; |
122 | 133 | } else { |
123 | - entry->fileName = NULL; | |
134 | + fprintf(stderr, "cde entry does not contain a file name.\n"); | |
135 | + return 1; | |
124 | 136 | } |
125 | 137 | p += entry->fileNameLength; |
138 | + remaining -= entry->fileNameLength; | |
126 | 139 | |
127 | - // extra field | |
140 | + // extra field, if any | |
128 | 141 | if (extraFieldLength != 0) { |
142 | + if (extraFieldLength > remaining) { | |
143 | + fprintf(stderr, "cde entry not large enough for extra field.\n"); | |
144 | + return 1; | |
145 | + } | |
146 | + | |
129 | 147 | extraField = p; |
130 | 148 | } else { |
131 | 149 | extraField = NULL; |
132 | 150 | } |
133 | 151 | p += extraFieldLength; |
152 | + remaining -= extraFieldLength; | |
134 | 153 | |
135 | 154 | // comment, if any |
136 | 155 | if (fileCommentLength != 0) { |
156 | + if (fileCommentLength > remaining) { | |
157 | + fprintf(stderr, "cde entry not large enough for file comment.\n"); | |
158 | + return 1; | |
159 | + } | |
160 | + | |
137 | 161 | fileComment = p; |
138 | 162 | } else { |
139 | 163 | fileComment = NULL; |
140 | 164 | } |
141 | 165 | p += fileCommentLength; |
166 | + remaining -= fileCommentLength; | |
142 | 167 | |
143 | 168 | *buf = p; |
169 | + *len = remaining; | |
144 | 170 | |
145 | 171 | // the size of the extraField in the central dir is how much data there is, |
146 | 172 | // but the one in the local file header also contains some padding. |
147 | 173 | p = file->buf + localHeaderRelOffset; |
174 | + if (p >= bufLimit) { | |
175 | + fprintf(stderr, "Invalid local header offset for entry.\n"); | |
176 | + return 1; | |
177 | + } | |
178 | + | |
148 | 179 | extraFieldLength = read_le_short(&p[0x1c]); |
149 | 180 | |
150 | 181 | dataOffset = localHeaderRelOffset + LFH_SIZE |
151 | 182 | + entry->fileNameLength + extraFieldLength; |
152 | 183 | entry->data = file->buf + dataOffset; |
184 | + | |
185 | + // Sanity check: make sure that the start of the entry data is within | |
186 | + // our allocated buffer. | |
187 | + if ((entry->data < file->buf) || (entry->data >= bufLimit)) { | |
188 | + fprintf(stderr, "Invalid data offset for entry.\n"); | |
189 | + return 1; | |
190 | + } | |
191 | + | |
192 | + // Sanity check: make sure that the end of the entry data is within | |
193 | + // our allocated buffer. We need to look at the uncompressedSize for | |
194 | + // stored entries and the compressed size for deflated entries. | |
195 | + if ((entry->compressionMethod == kCompressionStored) && | |
196 | + (entry->uncompressedSize > (unsigned int) (bufLimit - entry->data))) { | |
197 | + fprintf(stderr, "Invalid uncompressed size for stored entry.\n"); | |
198 | + return 1; | |
199 | + } | |
200 | + if ((entry->compressionMethod == kCompressionDeflate) && | |
201 | + (entry->compressedSize > (unsigned int) (bufLimit - entry->data))) { | |
202 | + fprintf(stderr, "Invalid uncompressed size for deflated entry.\n"); | |
203 | + return 1; | |
204 | + } | |
153 | 205 | #if 0 |
154 | 206 | printf("file->buf=%p entry->data=%p dataOffset=%x localHeaderRelOffset=%d " |
155 | 207 | "entry->fileNameLength=%d extraFieldLength=%d\n", |
@@ -75,7 +75,6 @@ main(int argc, char** argv) | ||
75 | 75 | unsize = get_zipentry_size(entry); |
76 | 76 | size = unsize * 1.001; |
77 | 77 | scratch = malloc(size); |
78 | - printf("scratch=%p\n", scratch); | |
79 | 78 | err = decompress_zipentry(entry, scratch, size); |
80 | 79 | if (err != 0) { |
81 | 80 | fprintf(stderr, "error decompressing file\n"); |