1 /*
2 * Copyright (c) 1995, 2020, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Oracle designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Oracle in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 * or visit www.oracle.com if you need additional information or have any
23 * questions.
24 */
25
26 /*
27 * Support for reading ZIP/JAR files.
28 */
29
30 #include <stdbool.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <stddef.h>
34 #include <string.h>
35 #include <fcntl.h>
36 #include <limits.h>
37 #include <time.h>
38 #include <ctype.h>
39 #include <assert.h>
40
41 #include "jni.h"
42 #include "jni_util.h"
43 #include "jlong.h"
44 #include "jvm.h"
45 #include "io_util.h"
46 #include "io_util_md.h"
47 #include "zip_util.h"
48 #include <zlib.h>
49
50 extern jmethodID jzOnZipEntryAccessID;
51
52 // Android-changed: Fuchsia: Alias *64 on Fuchsia builds. http://b/119496969
53 // #ifdef _ALLBSD_SOURCE
54 #if defined(_ALLBSD_SOURCE) || defined(__Fuchsia__)
55 #define off64_t off_t
56 #define mmap64 mmap
57 #endif
58
59 /* USE_MMAP means mmap the CEN & ENDHDR part of the zip file. */
60 #ifdef USE_MMAP
61 #include <sys/mman.h>
62 #endif
63
64 #define MAXREFS 0xFFFF /* max number of open zip file references */
65
66 #define MCREATE() JVM_RawMonitorCreate()
67 #define MLOCK(lock) JVM_RawMonitorEnter(lock)
68 #define MUNLOCK(lock) JVM_RawMonitorExit(lock)
69 #define MDESTROY(lock) JVM_RawMonitorDestroy(lock)
70
71 #define CENSIZE(cen) (CENHDR + CENNAM(cen) + CENEXT(cen) + CENCOM(cen))
72
73 static jzfile *zfiles = 0; /* currently open zip files */
74 static void *zfiles_lock = 0;
75
76 static void freeCEN(jzfile *);
77
78 #ifndef PATH_MAX
79 #define PATH_MAX 1024
80 #endif
81
82 static jint INITIAL_META_COUNT = 2; /* initial number of entries in meta name array */
83
84 /*
85 * Declare library specific JNI_Onload entry if static build
86 */
87 #ifdef STATIC_BUILD
88 DEF_STATIC_JNI_OnLoad
89 #endif
90
91 /*
92 * The ZFILE_* functions exist to provide some platform-independence with
93 * respect to file access needs.
94 */
95
96 /*
97 * Opens the named file for reading, returning a ZFILE.
98 *
99 * Compare this with winFileHandleOpen in windows/native/java/io/io_util_md.c.
100 * This function does not take JNIEnv* and uses CreateFile (instead of
101 * CreateFileW). The expectation is that this function will be called only
102 * from ZIP_Open_Generic, which in turn is used by the JVM, where we do not
103 * need to concern ourselves with wide chars.
104 */
105 static ZFILE
ZFILE_Open(const char * fname,int flags)106 ZFILE_Open(const char *fname, int flags) {
107 #ifdef WIN32
108 WCHAR *wfname, *wprefixed_fname;
109 size_t fname_length;
110 jlong fhandle;
111 const DWORD access =
112 (flags & O_RDWR) ? (GENERIC_WRITE | GENERIC_READ) :
113 (flags & O_WRONLY) ? GENERIC_WRITE :
114 GENERIC_READ;
115 const DWORD sharing =
116 FILE_SHARE_READ | FILE_SHARE_WRITE;
117 const DWORD disposition =
118 /* Note: O_TRUNC overrides O_CREAT */
119 (flags & O_TRUNC) ? CREATE_ALWAYS :
120 (flags & O_CREAT) ? OPEN_ALWAYS :
121 OPEN_EXISTING;
122 const DWORD maybeWriteThrough =
123 (flags & (O_SYNC | O_DSYNC)) ?
124 FILE_FLAG_WRITE_THROUGH :
125 FILE_ATTRIBUTE_NORMAL;
126 const DWORD maybeDeleteOnClose =
127 (flags & O_TEMPORARY) ?
128 FILE_FLAG_DELETE_ON_CLOSE :
129 FILE_ATTRIBUTE_NORMAL;
130 const DWORD flagsAndAttributes = maybeWriteThrough | maybeDeleteOnClose;
131
132 fname_length = strlen(fname);
133 if (fname_length < MAX_PATH) {
134 return (jlong)CreateFile(
135 fname, /* path name in multibyte char */
136 access, /* Read and/or write permission */
137 sharing, /* File sharing flags */
138 NULL, /* Security attributes */
139 disposition, /* creation disposition */
140 flagsAndAttributes, /* flags and attributes */
141 NULL);
142 } else {
143 /* Get required buffer size to convert to Unicode */
144 int wfname_len = MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS,
145 fname, -1, NULL, 0);
146 if (wfname_len == 0) {
147 return (jlong)INVALID_HANDLE_VALUE;
148 }
149 if ((wfname = (WCHAR*)malloc(wfname_len * sizeof(WCHAR))) == NULL) {
150 return (jlong)INVALID_HANDLE_VALUE;
151 }
152 if (MultiByteToWideChar(CP_ACP, MB_ERR_INVALID_CHARS,
153 fname, -1, wfname, wfname_len) == 0) {
154 free(wfname);
155 return (jlong)INVALID_HANDLE_VALUE;
156 }
157 wprefixed_fname = getPrefixed(wfname, (int)fname_length);
158 fhandle = (jlong)CreateFileW(
159 wprefixed_fname, /* Wide char path name */
160 access, /* Read and/or write permission */
161 sharing, /* File sharing flags */
162 NULL, /* Security attributes */
163 disposition, /* creation disposition */
164 flagsAndAttributes, /* flags and attributes */
165 NULL);
166 free(wfname);
167 free(wprefixed_fname);
168 return fhandle;
169 }
170 #else
171 return open(fname, flags, 0);
172 #endif
173 }
174
175 /*
176 * The io_util_md.h files do not provide IO_CLOSE, hence we use platform
177 * specifics.
178 */
179 static void
ZFILE_Close(ZFILE zfd)180 ZFILE_Close(ZFILE zfd) {
181 #ifdef WIN32
182 CloseHandle((HANDLE) zfd);
183 #else
184 close(zfd);
185 #endif
186 }
187
188 // Android-changed: also pass offset and use pread instead of read
189 // syscall. The former does not change file offset. See b/30407219.
190 static int
ZFILE_read(ZFILE zfd,char * buf,jint nbytes,jlong offset)191 ZFILE_read(ZFILE zfd, char *buf, jint nbytes, jlong offset) {
192 #ifdef WIN32
193 return (int) IO_Read(zfd, buf, nbytes);
194 #else
195 // return read(zfd, buf, nbytes);
196 return pread64(zfd, buf, nbytes, offset);
197 #endif
198 }
199
200 /*
201 * Initialize zip file support. Return 0 if successful otherwise -1
202 * if could not be initialized.
203 */
204 static jint
InitializeZip()205 InitializeZip()
206 {
207 static jboolean inited = JNI_FALSE;
208
209 // Initialize errno to 0. It may be set later (e.g. during memory
210 // allocation) but we can disregard previous values.
211 errno = 0;
212
213 if (inited)
214 return 0;
215 zfiles_lock = MCREATE();
216 if (zfiles_lock == 0) {
217 return -1;
218 }
219 inited = JNI_TRUE;
220
221 return 0;
222 }
223
224 /*
225 * Reads len bytes of data from the specified offset into buf.
226 * Returns 0 if all bytes could be read, otherwise returns -1.
227 */
228 static int
readFullyAt(ZFILE zfd,void * buf,jlong len,jlong offset)229 readFullyAt(ZFILE zfd, void *buf, jlong len, jlong offset) {
230 char *bp = (char *) buf;
231
232 while (len > 0) {
233 jlong limit = ((((jlong) 1) << 31) - 1);
234 jint count = (len < limit) ?
235 (jint) len :
236 (jint) limit;
237 jint n = ZFILE_read(zfd, bp, count, offset);
238 if (n > 0) {
239 bp += n;
240 offset += n;
241 len -= n;
242 } else if (n == -1 && errno == EINTR) {
243 /* Retry after EINTR (interrupted by signal). */
244 continue;
245 } else { /* EOF or IO error */
246 return -1;
247 }
248 }
249 return 0;
250 }
251
252
253 /*
254 * Allocates a new zip file object for the specified file name.
255 * Returns the zip file object or NULL if not enough memory.
256 */
257 static jzfile *
allocZip(const char * name)258 allocZip(const char *name)
259 {
260 jzfile *zip;
261 if (((zip = calloc(1, sizeof(jzfile))) != NULL) &&
262 ((zip->name = strdup(name)) != NULL) &&
263 ((zip->lock = MCREATE()) != NULL)) {
264 zip->zfd = -1;
265 return zip;
266 }
267
268 if (zip != NULL) {
269 free(zip->name);
270 free(zip);
271 }
272 return NULL;
273 }
274
275 /*
276 * Frees all native resources owned by the specified zip file object.
277 */
278 static void
freeZip(jzfile * zip)279 freeZip(jzfile *zip)
280 {
281 /* First free any cached jzentry */
282 ZIP_FreeEntry(zip,0);
283 if (zip->lock != NULL) MDESTROY(zip->lock);
284 free(zip->name);
285 freeCEN(zip);
286
287 #ifdef USE_MMAP
288 if (zip->usemmap) {
289 if (zip->maddr != NULL)
290 munmap((char *)zip->maddr, zip->mlen);
291 } else
292 #endif
293 {
294 free(zip->cencache.data);
295 }
296 if (zip->comment != NULL)
297 free(zip->comment);
298 if (zip->zfd != -1) ZFILE_Close(zip->zfd);
299 free(zip);
300 }
301
302 /* The END header is followed by a variable length comment of size < 64k. */
303 static const jlong END_MAXLEN = 0xFFFF + ENDHDR;
304
305 #define READBLOCKSZ 128
306
verifyEND(jzfile * zip,jlong endpos,char * endbuf)307 static jboolean verifyEND(jzfile *zip, jlong endpos, char *endbuf) {
308 /* ENDSIG matched, however the size of file comment in it does not
309 match the real size. One "common" cause for this problem is some
310 "extra" bytes are padded at the end of the zipfile.
311 Let's do some extra verification, we don't care about the performance
312 in this situation.
313 */
314 jlong cenpos = endpos - ENDSIZ(endbuf);
315 jlong locpos = cenpos - ENDOFF(endbuf);
316 char buf[4];
317 return (cenpos >= 0 &&
318 locpos >= 0 &&
319 readFullyAt(zip->zfd, buf, sizeof(buf), cenpos) != -1 &&
320 CENSIG_AT(buf) &&
321 readFullyAt(zip->zfd, buf, sizeof(buf), locpos) != -1 &&
322 LOCSIG_AT(buf));
323 }
324
325 /*
326 * Searches for end of central directory (END) header. The contents of
327 * the END header will be read and placed in endbuf. Returns the file
328 * position of the END header, otherwise returns -1 if the END header
329 * was not found or an error occurred.
330 */
331 static jlong
findEND(jzfile * zip,void * endbuf)332 findEND(jzfile *zip, void *endbuf)
333 {
334 char buf[READBLOCKSZ];
335 jlong pos;
336 const jlong len = zip->len;
337 const ZFILE zfd = zip->zfd;
338 const jlong minHDR = len - END_MAXLEN > 0 ? len - END_MAXLEN : 0;
339 // Android-changed: explicitly cast sizeof result to prevent sanitizer error.
340 const jlong minPos = minHDR - ((jlong)sizeof(buf)-ENDHDR);
341 jint clen;
342
343 for (pos = len - sizeof(buf); pos >= minPos; pos -= (sizeof(buf)-ENDHDR)) {
344
345 int i;
346 jlong off = 0;
347 if (pos < 0) {
348 /* Pretend there are some NUL bytes before start of file */
349 off = -pos;
350 memset(buf, '\0', (size_t)off);
351 }
352
353 if (readFullyAt(zfd, buf + off, sizeof(buf) - off,
354 pos + off) == -1) {
355 return -1; /* System error */
356 }
357
358 /* Now scan the block backwards for END header signature */
359 for (i = sizeof(buf) - ENDHDR; i >= 0; i--) {
360 if (buf[i+0] == 'P' &&
361 buf[i+1] == 'K' &&
362 buf[i+2] == '\005' &&
363 buf[i+3] == '\006' &&
364 ((pos + i + ENDHDR + ENDCOM(buf + i) == len)
365 || verifyEND(zip, pos + i, buf + i))) {
366 /* Found END header */
367 memcpy(endbuf, buf + i, ENDHDR);
368
369 clen = ENDCOM(endbuf);
370 if (clen != 0) {
371 zip->comment = malloc(clen + 1);
372 if (zip->comment == NULL) {
373 return -1;
374 }
375 if (readFullyAt(zfd, zip->comment, clen, pos + i + ENDHDR)
376 == -1) {
377 free(zip->comment);
378 zip->comment = NULL;
379 return -1;
380 }
381 zip->comment[clen] = '\0';
382 zip->clen = clen;
383 }
384 return pos + i;
385 }
386 }
387 }
388
389 return -1; /* END header not found */
390 }
391
392 /*
393 * Searches for the ZIP64 end of central directory (END) header. The
394 * contents of the ZIP64 END header will be read and placed in end64buf.
395 * Returns the file position of the ZIP64 END header, otherwise returns
396 * -1 if the END header was not found or an error occurred.
397 *
398 * The ZIP format specifies the "position" of each related record as
399 * ...
400 * [central directory]
401 * [zip64 end of central directory record]
402 * [zip64 end of central directory locator]
403 * [end of central directory record]
404 *
405 * The offset of zip64 end locator can be calculated from endpos as
406 * "endpos - ZIP64_LOCHDR".
407 * The "offset" of zip64 end record is stored in zip64 end locator.
408 */
409 static jlong
findEND64(jzfile * zip,void * end64buf,jlong endpos)410 findEND64(jzfile *zip, void *end64buf, jlong endpos)
411 {
412 char loc64[ZIP64_LOCHDR];
413 jlong end64pos;
414 if (readFullyAt(zip->zfd, loc64, ZIP64_LOCHDR, endpos - ZIP64_LOCHDR) == -1) {
415 return -1; // end64 locator not found
416 }
417 end64pos = ZIP64_LOCOFF(loc64);
418 if (readFullyAt(zip->zfd, end64buf, ZIP64_ENDHDR, end64pos) == -1) {
419 return -1; // end64 record not found
420 }
421 return end64pos;
422 }
423
424 // Android-changed: Commented-out an unused function
425 /*
426 * Returns a hash code value for a C-style NUL-terminated string.
427 */
428 // static unsigned int
429 // hash(const char *s)
430 // {
431 // int h = 0;
432 // while (*s != '\0')
433 // h = 31*h + *s++;
434 // return h;
435 // }
436
437 /*
438 * Returns a hash code value for a string of a specified length.
439 */
440 static unsigned int
hashN(const char * s,int length)441 hashN(const char *s, int length)
442 {
443 int h = 0;
444 while (length-- > 0)
445 h = 31*h + *s++;
446 return h;
447 }
448
449 /*
450 * Returns true if |s| is a valid zip entry name.
451 */
isValidEntryName(const char * s,int length)452 static bool isValidEntryName(const char *s, int length)
453 {
454 while (length-- > 0) {
455 if (*s++ == 0) {
456 return false;
457 }
458 }
459
460 return true;
461 }
462
463 static unsigned int
hash_append(unsigned int hash,char c)464 hash_append(unsigned int hash, char c)
465 {
466 return ((int)hash)*31 + c;
467 }
468
469 /*
470 * Returns true if the specified entry's name begins with the string
471 * "META-INF/".
472 */
473 static int
isMetaName(const char * name,int length)474 isMetaName(const char *name, int length)
475 {
476 static const char kMetaInf[] = "META-INF/";
477 static const int kMetaInfLength = sizeof(kMetaInf) - 1;
478 const char *s;
479 if (length < kMetaInfLength) {
480 return 0;
481 }
482
483 return (strncmp(kMetaInf, name, kMetaInfLength) == 0) ? 1 : 0;
484 }
485
486 /*
487 * Increases the capacity of zip->metanames.
488 * Returns non-zero in case of allocation error.
489 */
490 static int
growMetaNames(jzfile * zip)491 growMetaNames(jzfile *zip)
492 {
493 jint i;
494 /* double the meta names array */
495 const jint new_metacount = zip->metacount << 1;
496 zip->metanames =
497 realloc(zip->metanames, new_metacount * sizeof(zip->metanames[0]));
498 if (zip->metanames == NULL) return -1;
499 for (i = zip->metacount; i < new_metacount; i++)
500 zip->metanames[i] = NULL;
501 zip->metacurrent = zip->metacount;
502 zip->metacount = new_metacount;
503 return 0;
504 }
505
506 /*
507 * Adds name to zip->metanames.
508 * Returns non-zero in case of allocation error.
509 */
510 static int
addMetaName(jzfile * zip,const char * name,int length)511 addMetaName(jzfile *zip, const char *name, int length)
512 {
513 jint i;
514 if (zip->metanames == NULL) {
515 zip->metacount = INITIAL_META_COUNT;
516 zip->metanames = calloc(zip->metacount, sizeof(zip->metanames[0]));
517 if (zip->metanames == NULL) return -1;
518 zip->metacurrent = 0;
519 }
520
521 i = zip->metacurrent;
522
523 /* current meta name array isn't full yet. */
524 if (i < zip->metacount) {
525 zip->metanames[i] = (char *) malloc(length+1);
526 if (zip->metanames[i] == NULL) return -1;
527 memcpy(zip->metanames[i], name, length);
528 zip->metanames[i][length] = '\0';
529 zip->metacurrent++;
530 return 0;
531 }
532
533 /* No free entries in zip->metanames? */
534 if (growMetaNames(zip) != 0) return -1;
535 return addMetaName(zip, name, length);
536 }
537
538 static void
freeMetaNames(jzfile * zip)539 freeMetaNames(jzfile *zip)
540 {
541 if (zip->metanames) {
542 jint i;
543 for (i = 0; i < zip->metacount; i++)
544 free(zip->metanames[i]);
545 free(zip->metanames);
546 zip->metanames = NULL;
547 }
548 }
549
550 /* Free Zip data allocated by readCEN() */
551 static void
freeCEN(jzfile * zip)552 freeCEN(jzfile *zip)
553 {
554 free(zip->entries); zip->entries = NULL;
555 free(zip->table); zip->table = NULL;
556 freeMetaNames(zip);
557 }
558
559 /*
560 * Counts the number of CEN headers in a central directory extending
561 * from BEG to END. Might return a bogus answer if the zip file is
562 * corrupt, but will not crash.
563 */
564 static jint
countCENHeaders(unsigned char * beg,unsigned char * end)565 countCENHeaders(unsigned char *beg, unsigned char *end)
566 {
567 jint count = 0;
568 ptrdiff_t i;
569 for (i = 0; i + CENHDR <= end - beg; i += CENSIZE(beg + i))
570 count++;
571 return count;
572 }
573
574 #define ZIP_FORMAT_ERROR(message) \
575 if (1) { zip->msg = message; goto Catch; } else ((void)0)
576
577 // Android-added: Retrieve ZipFile's variable that determines if zip path validation is enabled.
isZipPathValidatorEnabled(JNIEnv * env,jobject thiz)578 static jboolean isZipPathValidatorEnabled(JNIEnv *env, jobject thiz) {
579 jclass cls = (*env)->FindClass(env, "java/util/zip/ZipFile");
580 jfieldID fid = (*env)->GetFieldID(env, cls, "isZipPathValidatorEnabled", "Z");
581 return (*env)->GetBooleanField(env, thiz, fid);
582 }
583
584 /*
585 * Reads zip file central directory. Returns the file position of first
586 * CEN header, otherwise returns -1 if an error occurred. If zip->msg != NULL
587 * then the error was a zip format error and zip->msg has the error text.
588 * Always pass in -1 for knownTotal; it's used for a recursive call.
589 */
590 static jlong
591 // Android changed: Pass jni env and thiz object into the method.
readCEN(JNIEnv * env,jobject thiz,jzfile * zip,jint knownTotal)592 readCEN(JNIEnv *env, jobject thiz, jzfile *zip, jint knownTotal)
593 {
594 /* Following are unsigned 32-bit */
595 jlong endpos, end64pos, cenpos, cenlen, cenoff;
596 /* Following are unsigned 16-bit */
597 jint total, tablelen, i, j;
598 unsigned char *cenbuf = NULL;
599 unsigned char *cenend;
600 unsigned char *cp;
601 #ifdef USE_MMAP
602 static jlong pagesize;
603 jlong offset;
604 #endif
605 unsigned char endbuf[ENDHDR];
606 jint endhdrlen = ENDHDR;
607 jzcell *entries;
608 jint *table;
609
610 /* Clear previous zip error */
611 zip->msg = NULL;
612 /* Get position of END header */
613 if ((endpos = findEND(zip, endbuf)) == -1)
614 return -1; /* no END header or system error */
615
616 if (endpos == 0) return 0; /* only END header present */
617
618 freeCEN(zip);
619 /* Get position and length of central directory */
620 cenlen = ENDSIZ(endbuf);
621 cenoff = ENDOFF(endbuf);
622 total = ENDTOT(endbuf);
623 if (cenlen == ZIP64_MAGICVAL || cenoff == ZIP64_MAGICVAL ||
624 total == ZIP64_MAGICCOUNT) {
625 unsigned char end64buf[ZIP64_ENDHDR];
626 if ((end64pos = findEND64(zip, end64buf, endpos)) != -1) {
627 cenlen = ZIP64_ENDSIZ(end64buf);
628 cenoff = ZIP64_ENDOFF(end64buf);
629 total = (jint)ZIP64_ENDTOT(end64buf);
630 endpos = end64pos;
631 endhdrlen = ZIP64_ENDHDR;
632 }
633 }
634
635 if (cenlen > endpos) {
636 ZIP_FORMAT_ERROR("invalid END header (bad central directory size)");
637 }
638 cenpos = endpos - cenlen;
639
640 /* Get position of first local file (LOC) header, taking into
641 * account that there may be a stub prefixed to the zip file. */
642 zip->locpos = cenpos - cenoff;
643 if (zip->locpos < 0) {
644 ZIP_FORMAT_ERROR("invalid END header (bad central directory offset)");
645 }
646 #ifdef USE_MMAP
647 if (zip->usemmap) {
648 /* On Solaris & Linux prior to JDK 6, we used to mmap the whole jar file to
649 * read the jar file contents. However, this greatly increased the perceived
650 * footprint numbers because the mmap'ed pages were adding into the totals shown
651 * by 'ps' and 'top'. We switched to mmaping only the central directory of jar
652 * file while calling 'read' to read the rest of jar file. Here are a list of
653 * reasons apart from above of why we are doing so:
654 * 1. Greatly reduces mmap overhead after startup complete;
655 * 2. Avoids dual path code maintainance;
656 * 3. Greatly reduces risk of address space (not virtual memory) exhaustion.
657 */
658 if (pagesize == 0) {
659 pagesize = (jlong)sysconf(_SC_PAGESIZE);
660 if (pagesize == 0) goto Catch;
661 }
662 if (cenpos > pagesize) {
663 offset = cenpos & ~(pagesize - 1);
664 } else {
665 offset = 0;
666 }
667 /* When we are not calling recursively, knownTotal is -1. */
668 if (knownTotal == -1) {
669 void* mappedAddr;
670 /* Mmap the CEN and END part only. We have to figure
671 out the page size in order to make offset to be multiples of
672 page size.
673 */
674 zip->mlen = cenpos - offset + cenlen + endhdrlen;
675 zip->offset = offset;
676 mappedAddr = mmap64(0, zip->mlen, PROT_READ, MAP_SHARED, zip->zfd, (off64_t) offset);
677 zip->maddr = (mappedAddr == (void*) MAP_FAILED) ? NULL :
678 (unsigned char*)mappedAddr;
679
680 if (zip->maddr == NULL) {
681 jio_fprintf(stderr, "mmap failed for CEN and END part of zip file\n");
682 goto Catch;
683 }
684 }
685 cenbuf = zip->maddr + cenpos - offset;
686 } else
687 #endif
688 {
689 if ((cenbuf = malloc((size_t) cenlen)) == NULL ||
690 (readFullyAt(zip->zfd, cenbuf, cenlen, cenpos) == -1))
691 goto Catch;
692 }
693
694 cenend = cenbuf + cenlen;
695
696 /* Initialize zip file data structures based on the total number
697 * of central directory entries as stored in ENDTOT. Since this
698 * is a 2-byte field, but we (and other zip implementations)
699 * support approx. 2**31 entries, we do not trust ENDTOT, but
700 * treat it only as a strong hint. When we call ourselves
701 * recursively, knownTotal will have the "true" value.
702 *
703 * Keep this path alive even with the Zip64 END support added, just
704 * for zip files that have more than 0xffff entries but don't have
705 * the Zip64 enabled.
706 */
707 total = (knownTotal != -1) ? knownTotal : total;
708 entries = zip->entries = calloc(total, sizeof(entries[0]));
709 tablelen = zip->tablelen = ((total/2) | 1); // Odd -> fewer collisions
710 table = zip->table = malloc(tablelen * sizeof(table[0]));
711 /* According to ISO C it is perfectly legal for malloc to return zero
712 * if called with a zero argument. We check this for 'entries' but not
713 * for 'table' because 'tablelen' can't be zero (see computation above). */
714 if ((entries == NULL && total != 0) || table == NULL) goto Catch;
715 for (j = 0; j < tablelen; j++)
716 table[j] = ZIP_ENDCHAIN;
717 // Android-added: Retrieve ZipFile's variable that determines if zip path validation is enabled.
718 jboolean isZipFilePathValidatorEnabled = isZipPathValidatorEnabled(env, thiz);
719 /* Iterate through the entries in the central directory */
720 for (i = 0, cp = cenbuf; cp <= cenend - CENHDR; i++, cp += CENSIZE(cp)) {
721 /* Following are unsigned 16-bit */
722 // Android-changed: A new variable flag because its value is used more than once.
723 jint method, nlen, flag;
724 unsigned int hsh;
725
726 if (i >= total) {
727 /* This will only happen if the zip file has an incorrect
728 * ENDTOT field, which usually means it contains more than
729 * 65535 entries. */
730 // Android changed: Pass jni env and thiz object into the method.
731 cenpos = readCEN(env, thiz, zip, countCENHeaders(cenbuf, cenend));
732 goto Finally;
733 }
734
735 method = CENHOW(cp);
736 nlen = CENNAM(cp);
737 // Android-added: A new variable flag because its value is used more than once.
738 flag = CENFLG(cp);
739
740 if (!CENSIG_AT(cp)) {
741 ZIP_FORMAT_ERROR("invalid CEN header (bad signature)");
742 }
743 // Android-changed: Use of the flag variable instead of the direct call to CENFLG.
744 if (flag & 1) {
745 ZIP_FORMAT_ERROR("invalid CEN header (encrypted entry)");
746 }
747 if (method != STORED && method != DEFLATED) {
748 ZIP_FORMAT_ERROR("invalid CEN header (bad compression method)");
749 }
750 if (cp + CENHDR + nlen > cenend) {
751 ZIP_FORMAT_ERROR("invalid CEN header (bad header size)");
752 }
753
754 // BEGIN Android-changed: Use strict mode to validate zip entry name,
755 // and throw exception if policy throws exception.
756 const char* entryName = (const char *)cp + CENHDR;
757 if (!isValidEntryName(entryName, nlen)) {
758 ZIP_FORMAT_ERROR("invalid CEN header (invalid entry name)");
759 }
760 if (isZipFilePathValidatorEnabled &&
761 ZIP_OnZipEntryAccess(env, thiz, entryName, nlen, flag)) {
762 ZIP_FORMAT_ERROR("restricted zip entry name");
763 }
764 // END Android-changed: Use strict mode to validate zip entry name,
765 // and throw exception if policy throws exception.
766
767 /* if the entry is metadata add it to our metadata names */
768 if (isMetaName(entryName, nlen)) {
769 if (addMetaName(zip, (char *)cp+CENHDR, nlen) != 0) {
770 goto Catch;
771 }
772 }
773
774 /* Record the CEN offset and the name hash in our hash cell. */
775 entries[i].cenpos = cenpos + (cp - cenbuf);
776 entries[i].hash = hashN(entryName, nlen);
777 entries[i].next = ZIP_ENDCHAIN;
778
779 /* Add the entry to the hash table */
780 hsh = entries[i].hash % tablelen;
781
782 /* First check that there are no other entries that have the same name. */
783 int chain = table[hsh];
784 while (chain != ZIP_ENDCHAIN) {
785 const jzcell* cell = &entries[chain];
786 if (cell->hash == entries[i].hash) {
787 const char* cenStart = (const char *) cenbuf + cell->cenpos - cenpos;
788 if (CENNAM(cenStart) == nlen) {
789 const char* chainName = cenStart + CENHDR;
790 if (strncmp(entryName, chainName, nlen) == 0) {
791 ZIP_FORMAT_ERROR("invalid CEN header (duplicate entry)");
792 }
793 }
794 }
795
796 chain = cell->next;
797 }
798
799
800 entries[i].next = table[hsh];
801 table[hsh] = i;
802 }
803 if (cp != cenend) {
804 ZIP_FORMAT_ERROR("invalid CEN header (bad header size)");
805 }
806 zip->total = i;
807 goto Finally;
808
809 Catch:
810 freeCEN(zip);
811 cenpos = -1;
812
813 Finally:
814 #ifdef USE_MMAP
815 if (!zip->usemmap)
816 #endif
817 free(cenbuf);
818
819 return cenpos;
820 }
821
822 /*
823 * Opens a zip file with the specified mode. Returns the jzfile object
824 * or NULL if an error occurred. If a zip error occurred then *pmsg will
825 * be set to the error message text if pmsg != 0. Otherwise, *pmsg will be
826 * set to NULL. Caller is responsible to free the error message.
827 */
828 jzfile *
829 // Android changed: Pass jni env and thiz object into the method.
ZIP_Open_Generic(JNIEnv * env,jobject thiz,const char * name,char ** pmsg,int mode,jlong lastModified)830 ZIP_Open_Generic(JNIEnv *env, jobject thiz, const char *name, char **pmsg, int mode, jlong lastModified)
831 {
832 jzfile *zip = NULL;
833
834 /* Clear zip error message */
835 // BEGIN Android-changed: Don't crash crash if `pmsg` is NULL and getting from the cache fails.
836 /*
837 if (pmsg != NULL) {
838 *pmsg = NULL;
839 }
840
841 zip = ZIP_Get_From_Cache(name, pmsg, lastModified);
842
843 if (zip == NULL && pmsg != NULL && *pmsg == NULL) {
844 ZFILE zfd = ZFILE_Open(name, mode);
845 zip = ZIP_Put_In_Cache(name, zfd, pmsg, lastModified);
846 }
847 */
848 /*
849 * We want to know if ZIP_Get_From_Cache fails, which isn't possible to
850 * distinguish without passing a non-null message value. Hence, if the user
851 * didn't supply a `pmsg`, we make and manage our own.
852 */
853 char *localPmsg = NULL;
854 zip = ZIP_Get_From_Cache(name, &localPmsg, lastModified);
855
856 if (zip == NULL && localPmsg == NULL) {
857 ZFILE zfd = ZFILE_Open(name, mode);
858 // Android changed: Pass jni env and thiz object into the method.
859 zip = ZIP_Put_In_Cache(env, thiz, name, zfd, &localPmsg, lastModified);
860 }
861
862 if (pmsg == NULL) {
863 free(localPmsg);
864 } else {
865 *pmsg = localPmsg;
866 }
867 // END Android-changed: Don't crash crash if `pmsg` is NULL and getting from the cache fails.
868 return zip;
869 }
870
871 /*
872 * Returns the jzfile corresponding to the given file name from the cache of
873 * zip files, or NULL if the file is not in the cache. If the name is longer
874 * than PATH_MAX or a zip error occurred then *pmsg will be set to the error
875 * message text if pmsg != 0. Otherwise, *pmsg will be set to NULL. Caller
876 * is responsible to free the error message.
877 */
878 jzfile *
ZIP_Get_From_Cache(const char * name,char ** pmsg,jlong lastModified)879 ZIP_Get_From_Cache(const char *name, char **pmsg, jlong lastModified)
880 {
881 char buf[PATH_MAX];
882 jzfile *zip;
883
884 if (InitializeZip()) {
885 return NULL;
886 }
887
888 /* Clear zip error message */
889 if (pmsg != 0) {
890 *pmsg = NULL;
891 }
892
893 if (strlen(name) >= PATH_MAX) {
894 if (pmsg) {
895 *pmsg = strdup("zip file name too long");
896 }
897 return NULL;
898 }
899 strcpy(buf, name);
900 JVM_NativePath(buf);
901 name = buf;
902
903 MLOCK(zfiles_lock);
904 for (zip = zfiles; zip != NULL; zip = zip->next) {
905 if (strcmp(name, zip->name) == 0
906 && (zip->lastModified == lastModified || zip->lastModified == 0)
907 && zip->refs < MAXREFS) {
908 zip->refs++;
909 break;
910 }
911 }
912 MUNLOCK(zfiles_lock);
913 return zip;
914 }
915
916 /*
917 * Reads data from the given file descriptor to create a jzfile, puts the
918 * jzfile in a cache, and returns that jzfile. Returns NULL in case of error.
919 * If a zip error occurs, then *pmsg will be set to the error message text if
920 * pmsg != 0. Otherwise, *pmsg will be set to NULL. Caller is responsible to
921 * free the error message.
922 */
923
924 jzfile *
925 // Android changed: Pass jni env and thiz object into the method.
ZIP_Put_In_Cache(JNIEnv * env,jobject thiz,const char * name,ZFILE zfd,char ** pmsg,jlong lastModified)926 ZIP_Put_In_Cache(JNIEnv *env, jobject thiz, const char *name, ZFILE zfd, char **pmsg, jlong lastModified)
927 {
928 // Android changed: Pass jni env and thiz object into the method.
929 return ZIP_Put_In_Cache0(env, thiz, name, zfd, pmsg, lastModified, JNI_TRUE);
930 }
931
932 jzfile *
933 // Android changed: Pass jni env and thiz object into the method.
ZIP_Put_In_Cache0(JNIEnv * env,jobject thiz,const char * name,ZFILE zfd,char ** pmsg,jlong lastModified,jboolean usemmap)934 ZIP_Put_In_Cache0(JNIEnv *env, jobject thiz, const char *name, ZFILE zfd, char **pmsg, jlong lastModified,
935 jboolean usemmap)
936 {
937 char errbuf[256];
938 jlong len;
939 jzfile *zip;
940
941 if ((zip = allocZip(name)) == NULL) {
942 return NULL;
943 }
944
945 #ifdef USE_MMAP
946 zip->usemmap = usemmap;
947 #endif
948 zip->refs = 1;
949 zip->lastModified = lastModified;
950
951 if (zfd == -1) {
952 if (pmsg && getLastErrorString(errbuf, sizeof(errbuf)) > 0)
953 *pmsg = strdup(errbuf);
954 freeZip(zip);
955 return NULL;
956 }
957
958 // Assumption, zfd refers to start of file. Trivially, reuse errbuf.
959 if (readFullyAt(zfd, errbuf, 4, 0 /* offset */) != -1) { // errors will be handled later
960 zip->locsig = LOCSIG_AT(errbuf) ? JNI_TRUE : JNI_FALSE;
961 }
962
963 // This lseek is safe because it happens during construction of the ZipFile
964 // object. We must take care not to perform any operations that change the
965 // offset after (see b/30407219).
966 len = zip->len = IO_Lseek(zfd, 0, SEEK_END);
967 if (len <= 0) {
968 if (len == 0) { /* zip file is empty */
969 if (pmsg) {
970 *pmsg = strdup("zip file is empty");
971 }
972 } else { /* error */
973 if (pmsg && getLastErrorString(errbuf, sizeof(errbuf)) > 0)
974 *pmsg = strdup(errbuf);
975 }
976 ZFILE_Close(zfd);
977 freeZip(zip);
978 return NULL;
979 }
980
981 zip->zfd = zfd;
982 // Android changed: Pass jni env and thiz object into the method.
983 if (readCEN(env, thiz, zip, -1) < 0) {
984 /* An error occurred while trying to read the zip file */
985 if (pmsg != 0) {
986 /* Set the zip error message */
987 if (zip->msg != NULL)
988 *pmsg = strdup(zip->msg);
989 }
990 freeZip(zip);
991 return NULL;
992 }
993 MLOCK(zfiles_lock);
994 zip->next = zfiles;
995 zfiles = zip;
996 MUNLOCK(zfiles_lock);
997
998 return zip;
999 }
1000
1001 /*
1002 * Opens a zip file for reading. Returns the jzfile object or NULL
1003 * if an error occurred. If a zip error occurred then *msg will be
1004 * set to the error message text if msg != 0. Otherwise, *msg will be
1005 * set to NULL. Caller doesn't need to free the error message.
1006 */
1007 JNIEXPORT jzfile *
1008 // Android changed: Pass jni env and thiz object into the method.
ZIP_Open(JNIEnv * env,jobject thiz,const char * name,char ** pmsg)1009 ZIP_Open(JNIEnv *env, jobject thiz, const char *name, char **pmsg)
1010 {
1011 // Android changed: Pass jni env and thiz object into the method.
1012 jzfile *file = ZIP_Open_Generic(env, thiz, name, pmsg, O_RDONLY, 0);
1013 if (file == NULL && pmsg != NULL && *pmsg != NULL) {
1014 free(*pmsg);
1015 *pmsg = "Zip file open error";
1016 }
1017 return file;
1018 }
1019
1020 /*
1021 * Closes the specified zip file object.
1022 */
1023 JNIEXPORT void
ZIP_Close(jzfile * zip)1024 ZIP_Close(jzfile *zip)
1025 {
1026 MLOCK(zfiles_lock);
1027 if (--zip->refs > 0) {
1028 /* Still more references so just return */
1029 MUNLOCK(zfiles_lock);
1030 return;
1031 }
1032 /* No other references so close the file and remove from list */
1033 if (zfiles == zip) {
1034 zfiles = zfiles->next;
1035 } else {
1036 jzfile *zp;
1037 for (zp = zfiles; zp->next != 0; zp = zp->next) {
1038 if (zp->next == zip) {
1039 zp->next = zip->next;
1040 break;
1041 }
1042 }
1043 }
1044 MUNLOCK(zfiles_lock);
1045 freeZip(zip);
1046 return;
1047 }
1048
1049 /* Empirically, most CEN headers are smaller than this. */
1050 #define AMPLE_CEN_HEADER_SIZE 160
1051
1052 /* A good buffer size when we want to read CEN headers sequentially. */
1053 #define CENCACHE_PAGESIZE 8192
1054
1055 static char *
readCENHeader(jzfile * zip,jlong cenpos,jint bufsize)1056 readCENHeader(jzfile *zip, jlong cenpos, jint bufsize)
1057 {
1058 jint censize;
1059 ZFILE zfd = zip->zfd;
1060 char *cen;
1061 if (bufsize > zip->len - cenpos)
1062 bufsize = (jint)(zip->len - cenpos);
1063 if ((cen = malloc(bufsize)) == NULL) goto Catch;
1064 if (readFullyAt(zfd, cen, bufsize, cenpos) == -1) goto Catch;
1065 censize = CENSIZE(cen);
1066 if (censize <= bufsize) return cen;
1067 if ((cen = realloc(cen, censize)) == NULL) goto Catch;
1068 if (readFullyAt(zfd, cen+bufsize, censize-bufsize, cenpos + bufsize) == -1) goto Catch;
1069 return cen;
1070
1071 Catch:
1072 free(cen);
1073 return NULL;
1074 }
1075
1076 static char *
sequentialAccessReadCENHeader(jzfile * zip,jlong cenpos)1077 sequentialAccessReadCENHeader(jzfile *zip, jlong cenpos)
1078 {
1079 cencache *cache = &zip->cencache;
1080 char *cen;
1081 if (cache->data != NULL
1082 && (cenpos >= cache->pos)
1083 && (cenpos + CENHDR <= cache->pos + CENCACHE_PAGESIZE))
1084 {
1085 cen = cache->data + cenpos - cache->pos;
1086 if (cenpos + CENSIZE(cen) <= cache->pos + CENCACHE_PAGESIZE)
1087 /* A cache hit */
1088 return cen;
1089 }
1090
1091 if ((cen = readCENHeader(zip, cenpos, CENCACHE_PAGESIZE)) == NULL)
1092 return NULL;
1093 free(cache->data);
1094 cache->data = cen;
1095 cache->pos = cenpos;
1096 return cen;
1097 }
1098
1099 typedef enum { ACCESS_RANDOM, ACCESS_SEQUENTIAL } AccessHint;
1100
1101 /*
1102 * Return a new initialized jzentry corresponding to a given hash cell.
1103 * In case of error, returns NULL.
1104 * We already sanity-checked all the CEN headers for ZIP format errors
1105 * in readCEN(), so we don't check them again here.
1106 * The ZIP lock should be held here.
1107 */
1108 static jzentry *
newEntry(jzfile * zip,jzcell * zc,AccessHint accessHint)1109 newEntry(jzfile *zip, jzcell *zc, AccessHint accessHint)
1110 {
1111 jlong locoff;
1112 jint nlen, elen, clen;
1113 jzentry *ze;
1114 char *cen;
1115
1116 if ((ze = (jzentry *) malloc(sizeof(jzentry))) == NULL) return NULL;
1117 ze->name = NULL;
1118 ze->extra = NULL;
1119 ze->comment = NULL;
1120
1121 #ifdef USE_MMAP
1122 if (zip->usemmap) {
1123 cen = (char*) zip->maddr + zc->cenpos - zip->offset;
1124 } else
1125 #endif
1126 {
1127 if (accessHint == ACCESS_RANDOM)
1128 cen = readCENHeader(zip, zc->cenpos, AMPLE_CEN_HEADER_SIZE);
1129 else
1130 cen = sequentialAccessReadCENHeader(zip, zc->cenpos);
1131 if (cen == NULL) goto Catch;
1132 }
1133
1134 nlen = CENNAM(cen);
1135 elen = CENEXT(cen);
1136 clen = CENCOM(cen);
1137 ze->time = CENTIM(cen);
1138 ze->size = CENLEN(cen);
1139 ze->csize = (CENHOW(cen) == STORED) ? 0 : CENSIZ(cen);
1140 ze->crc = CENCRC(cen);
1141 locoff = CENOFF(cen);
1142 ze->pos = -(zip->locpos + locoff);
1143 ze->flag = CENFLG(cen);
1144
1145 if ((ze->name = malloc(nlen + 1)) == NULL) goto Catch;
1146 memcpy(ze->name, cen + CENHDR, nlen);
1147 ze->name[nlen] = '\0';
1148 ze->nlen = nlen;
1149 if (elen > 0) {
1150 char *extra = cen + CENHDR + nlen;
1151
1152 /* This entry has "extra" data */
1153 if ((ze->extra = malloc(elen + 2)) == NULL) goto Catch;
1154 ze->extra[0] = (unsigned char) elen;
1155 ze->extra[1] = (unsigned char) (elen >> 8);
1156 memcpy(ze->extra+2, extra, elen);
1157 if (ze->csize == ZIP64_MAGICVAL || ze->size == ZIP64_MAGICVAL ||
1158 locoff == ZIP64_MAGICVAL) {
1159 jint off = 0;
1160 while ((off + 4) < elen) { // spec: HeaderID+DataSize+Data
1161 jint sz = SH(extra, off + 2);
1162 if (SH(extra, off) == ZIP64_EXTID) {
1163 off += 4;
1164 if (ze->size == ZIP64_MAGICVAL) {
1165 // if invalid zip64 extra fields, just skip
1166 if (sz < 8 || (off + 8) > elen)
1167 break;
1168 ze->size = LL(extra, off);
1169 sz -= 8;
1170 off += 8;
1171 }
1172 if (ze->csize == ZIP64_MAGICVAL) {
1173 if (sz < 8 || (off + 8) > elen)
1174 break;
1175 ze->csize = LL(extra, off);
1176 sz -= 8;
1177 off += 8;
1178 }
1179 if (locoff == ZIP64_MAGICVAL) {
1180 if (sz < 8 || (off + 8) > elen)
1181 break;
1182 ze->pos = -(zip->locpos + LL(extra, off));
1183 sz -= 8;
1184 off += 8;
1185 }
1186 break;
1187 }
1188 off += (sz + 4);
1189 }
1190 }
1191 }
1192
1193 if (clen > 0) {
1194 /* This entry has a comment */
1195 if ((ze->comment = malloc(clen + 1)) == NULL) goto Catch;
1196 memcpy(ze->comment, cen + CENHDR + nlen + elen, clen);
1197 ze->comment[clen] = '\0';
1198 }
1199 goto Finally;
1200
1201 Catch:
1202 free(ze->name);
1203 free(ze->extra);
1204 free(ze->comment);
1205 free(ze);
1206 ze = NULL;
1207
1208 Finally:
1209 #ifdef USE_MMAP
1210 if (!zip->usemmap)
1211 #endif
1212 if (cen != NULL && accessHint == ACCESS_RANDOM) free(cen);
1213 return ze;
1214 }
1215
1216 /*
1217 * Free the given jzentry.
1218 * In fact we maintain a one-entry cache of the most recently used
1219 * jzentry for each zip. This optimizes a common access pattern.
1220 */
1221
1222 void
ZIP_FreeEntry(jzfile * jz,jzentry * ze)1223 ZIP_FreeEntry(jzfile *jz, jzentry *ze)
1224 {
1225 jzentry *last;
1226 ZIP_Lock(jz);
1227 last = jz->cache;
1228 jz->cache = ze;
1229 ZIP_Unlock(jz);
1230 if (last != NULL) {
1231 /* Free the previously cached jzentry */
1232 free(last->name);
1233 if (last->extra) free(last->extra);
1234 if (last->comment) free(last->comment);
1235 free(last);
1236 }
1237 }
1238
1239 /*
1240 * Returns the zip entry corresponding to the specified name, or
1241 * NULL if not found.
1242 */
1243 jzentry *
ZIP_GetEntry(jzfile * zip,char * name,jint ulen)1244 ZIP_GetEntry(jzfile *zip, char *name, jint ulen)
1245 {
1246 if (ulen == 0) {
1247 return ZIP_GetEntry2(zip, name, (jint)strlen(name), JNI_FALSE);
1248 }
1249 return ZIP_GetEntry2(zip, name, ulen, JNI_TRUE);
1250 }
1251
equals(char * name1,int len1,char * name2,int len2)1252 jboolean equals(char* name1, int len1, char* name2, int len2) {
1253 if (len1 != len2) {
1254 return JNI_FALSE;
1255 }
1256 while (len1-- > 0) {
1257 if (*name1++ != *name2++) {
1258 return JNI_FALSE;
1259 }
1260 }
1261 return JNI_TRUE;
1262 }
1263
1264 /*
1265 * Returns the zip entry corresponding to the specified name, or
1266 * NULL if not found.
1267 * This method supports embedded null character in "name", use ulen
1268 * for the length of "name".
1269 */
1270 jzentry *
ZIP_GetEntry2(jzfile * zip,char * name,jint ulen,jboolean addSlash)1271 ZIP_GetEntry2(jzfile *zip, char *name, jint ulen, jboolean addSlash)
1272 {
1273 unsigned int hsh = hashN(name, ulen);
1274 jint idx;
1275 jzentry *ze = 0;
1276
1277 ZIP_Lock(zip);
1278 if (zip->total == 0) {
1279 goto Finally;
1280 }
1281
1282 idx = zip->table[hsh % zip->tablelen];
1283
1284 /*
1285 * This while loop is an optimization where a double lookup
1286 * for name and name+/ is being performed. The name char
1287 * array has enough room at the end to try again with a
1288 * slash appended if the first table lookup does not succeed.
1289 */
1290 while(1) {
1291
1292 /* Check the cached entry first */
1293 ze = zip->cache;
1294 if (ze && equals(ze->name, ze->nlen, name, ulen)) {
1295 /* Cache hit! Remove and return the cached entry. */
1296 zip->cache = 0;
1297 ZIP_Unlock(zip);
1298 return ze;
1299 }
1300 ze = 0;
1301
1302 /*
1303 * Search down the target hash chain for a cell whose
1304 * 32 bit hash matches the hashed name.
1305 */
1306 while (idx != ZIP_ENDCHAIN) {
1307 jzcell *zc = &zip->entries[idx];
1308
1309 if (zc->hash == hsh) {
1310 /*
1311 * OK, we've found a ZIP entry whose 32 bit hashcode
1312 * matches the name we're looking for. Try to read
1313 * its entry information from the CEN. If the CEN
1314 * name matches the name we're looking for, we're
1315 * done.
1316 * If the names don't match (which should be very rare)
1317 * we keep searching.
1318 */
1319 ze = newEntry(zip, zc, ACCESS_RANDOM);
1320 if (ze && equals(ze->name, ze->nlen, name, ulen)) {
1321 break;
1322 }
1323 if (ze != 0) {
1324 /* We need to release the lock across the free call */
1325 ZIP_Unlock(zip);
1326 ZIP_FreeEntry(zip, ze);
1327 ZIP_Lock(zip);
1328 }
1329 ze = 0;
1330 }
1331 idx = zc->next;
1332 }
1333
1334 /* Entry found, return it */
1335 if (ze != 0) {
1336 break;
1337 }
1338
1339 /* If no need to try appending slash, we are done */
1340 if (!addSlash) {
1341 break;
1342 }
1343
1344 /* Slash is already there? */
1345 if (ulen > 0 && name[ulen - 1] == '/') {
1346 break;
1347 }
1348
1349 /* Add slash and try once more */
1350 name[ulen++] = '/';
1351 name[ulen] = '\0';
1352 hsh = hash_append(hsh, '/');
1353 idx = zip->table[hsh % zip->tablelen];
1354 addSlash = JNI_FALSE;
1355 }
1356
1357 Finally:
1358 ZIP_Unlock(zip);
1359 return ze;
1360 }
1361
1362 /*
1363 * Returns the n'th (starting at zero) zip file entry, or NULL if the
1364 * specified index was out of range.
1365 */
1366 JNIEXPORT jzentry *
ZIP_GetNextEntry(jzfile * zip,jint n)1367 ZIP_GetNextEntry(jzfile *zip, jint n)
1368 {
1369 jzentry *result;
1370 if (n < 0 || n >= zip->total) {
1371 return 0;
1372 }
1373 ZIP_Lock(zip);
1374 result = newEntry(zip, &zip->entries[n], ACCESS_SEQUENTIAL);
1375 ZIP_Unlock(zip);
1376 return result;
1377 }
1378
1379 /*
1380 * Locks the specified zip file for reading.
1381 */
1382 void
ZIP_Lock(jzfile * zip)1383 ZIP_Lock(jzfile *zip)
1384 {
1385 MLOCK(zip->lock);
1386 }
1387
1388 /*
1389 * Unlocks the specified zip file.
1390 */
1391 void
ZIP_Unlock(jzfile * zip)1392 ZIP_Unlock(jzfile *zip)
1393 {
1394 MUNLOCK(zip->lock);
1395 }
1396
1397 /*
1398 * Returns the offset of the entry data within the zip file.
1399 * Returns -1 if an error occurred, in which case zip->msg will
1400 * contain the error text.
1401 */
1402 jlong
ZIP_GetEntryDataOffset(jzfile * zip,jzentry * entry)1403 ZIP_GetEntryDataOffset(jzfile *zip, jzentry *entry)
1404 {
1405 /* The Zip file spec explicitly allows the LOC extra data size to
1406 * be different from the CEN extra data size, although the JDK
1407 * never creates such zip files. Since we cannot trust the CEN
1408 * extra data size, we need to read the LOC to determine the entry
1409 * data offset. We do this lazily to avoid touching the virtual
1410 * memory page containing the LOC when initializing jzentry
1411 * objects. (This speeds up javac by a factor of 10 when the JDK
1412 * is installed on a very slow filesystem.)
1413 */
1414 if (entry->pos <= 0) {
1415 unsigned char loc[LOCHDR];
1416 if (readFullyAt(zip->zfd, loc, LOCHDR, -(entry->pos)) == -1) {
1417 zip->msg = "error reading zip file";
1418 return -1;
1419 }
1420 if (!LOCSIG_AT(loc)) {
1421 zip->msg = "invalid LOC header (bad signature)";
1422 return -1;
1423 }
1424 entry->pos = (- entry->pos) + LOCHDR + LOCNAM(loc) + LOCEXT(loc);
1425 }
1426 return entry->pos;
1427 }
1428
1429 /*
1430 * Reads bytes from the specified zip entry. Assumes that the zip
1431 * file had been previously locked with ZIP_Lock(). Returns the
1432 * number of bytes read, or -1 if an error occurred. If zip->msg != 0
1433 * then a zip error occurred and zip->msg contains the error text.
1434 *
1435 * The current implementation does not support reading an entry that
1436 * has the size bigger than 2**32 bytes in ONE invocation.
1437 */
1438 jint
ZIP_Read(jzfile * zip,jzentry * entry,jlong pos,void * buf,jint len)1439 ZIP_Read(jzfile *zip, jzentry *entry, jlong pos, void *buf, jint len)
1440 {
1441 jlong entry_size;
1442 jlong start;
1443
1444 if (zip == 0) {
1445 return -1;
1446 }
1447
1448 /* Clear previous zip error */
1449 zip->msg = NULL;
1450
1451 if (entry == 0) {
1452 zip->msg = "ZIP_Read: jzentry is NULL";
1453 return -1;
1454 }
1455
1456 entry_size = (entry->csize != 0) ? entry->csize : entry->size;
1457
1458 /* Check specified position */
1459 if (pos < 0 || pos > entry_size - 1) {
1460 zip->msg = "ZIP_Read: specified offset out of range";
1461 return -1;
1462 }
1463
1464 /* Check specified length */
1465 if (len <= 0)
1466 return 0;
1467 if (len > entry_size - pos)
1468 len = (jint)(entry_size - pos);
1469
1470 /* Get file offset to start reading data */
1471 start = ZIP_GetEntryDataOffset(zip, entry);
1472 if (start < 0)
1473 return -1;
1474 start += pos;
1475
1476 if (start + len > zip->len) {
1477 zip->msg = "ZIP_Read: corrupt zip file: invalid entry size";
1478 return -1;
1479 }
1480
1481 if (readFullyAt(zip->zfd, buf, len, start) == -1) {
1482 zip->msg = "ZIP_Read: error reading zip file";
1483 return -1;
1484 }
1485 return len;
1486 }
1487
1488
1489 /* The maximum size of a stack-allocated buffer.
1490 */
1491 #define BUF_SIZE 4096
1492
1493 /*
1494 * This function is used by the runtime system to load compressed entries
1495 * from ZIP/JAR files specified in the class path. It is defined here
1496 * so that it can be dynamically loaded by the runtime if the zip library
1497 * is found.
1498 *
1499 * The current implementation does not support reading an entry that
1500 * has the size bigger than 2**32 bytes in ONE invocation.
1501 */
1502 jboolean
InflateFully(jzfile * zip,jzentry * entry,void * buf,char ** msg)1503 InflateFully(jzfile *zip, jzentry *entry, void *buf, char **msg)
1504 {
1505 z_stream strm;
1506 char tmp[BUF_SIZE];
1507 jlong pos = 0;
1508 jlong count = entry->csize;
1509
1510 *msg = 0; /* Reset error message */
1511
1512 if (count == 0) {
1513 *msg = "inflateFully: entry not compressed";
1514 return JNI_FALSE;
1515 }
1516
1517 memset(&strm, 0, sizeof(z_stream));
1518 if (inflateInit2(&strm, -MAX_WBITS) != Z_OK) {
1519 *msg = strm.msg;
1520 return JNI_FALSE;
1521 }
1522
1523 strm.next_out = buf;
1524 strm.avail_out = (uInt)entry->size;
1525
1526 while (count > 0) {
1527 jint n = count > (jlong)sizeof(tmp) ? (jint)sizeof(tmp) : (jint)count;
1528 ZIP_Lock(zip);
1529 n = ZIP_Read(zip, entry, pos, tmp, n);
1530 ZIP_Unlock(zip);
1531 if (n <= 0) {
1532 if (n == 0) {
1533 *msg = "inflateFully: Unexpected end of file";
1534 }
1535 inflateEnd(&strm);
1536 return JNI_FALSE;
1537 }
1538 pos += n;
1539 count -= n;
1540 strm.next_in = (Bytef *)tmp;
1541 strm.avail_in = n;
1542 do {
1543 switch (inflate(&strm, Z_PARTIAL_FLUSH)) {
1544 case Z_OK:
1545 break;
1546 case Z_STREAM_END:
1547 // Android-changed: added entry->size < 0 check.
1548 // if (count != 0 || strm.total_out != (uInt)entry->size) {
1549 if (count != 0 || entry->size < 0 || strm.total_out != (uint64_t)entry->size) {
1550 *msg = "inflateFully: Unexpected end of stream";
1551 inflateEnd(&strm);
1552 return JNI_FALSE;
1553 }
1554 break;
1555 default:
1556 break;
1557 }
1558 } while (strm.avail_in > 0);
1559 }
1560
1561 inflateEnd(&strm);
1562 return JNI_TRUE;
1563 }
1564
1565 /*
1566 * The current implementation does not support reading an entry that
1567 * has the size bigger than 2**32 bytes in ONE invocation.
1568 */
1569 JNIEXPORT jzentry *
ZIP_FindEntry(jzfile * zip,char * name,jint * sizeP,jint * nameLenP)1570 ZIP_FindEntry(jzfile *zip, char *name, jint *sizeP, jint *nameLenP)
1571 {
1572 jzentry *entry = ZIP_GetEntry(zip, name, 0);
1573 if (entry) {
1574 *sizeP = (jint)entry->size;
1575 *nameLenP = (jint)strlen(entry->name);
1576 }
1577 return entry;
1578 }
1579
1580 /*
1581 * Reads a zip file entry into the specified byte array
1582 * When the method completes, it releases the jzentry.
1583 * Note: this is called from the separately delivered VM (hotspot/classic)
1584 * so we have to be careful to maintain the expected behaviour.
1585 */
1586 JNIEXPORT jboolean
ZIP_ReadEntry(jzfile * zip,jzentry * entry,unsigned char * buf,char * entryname)1587 ZIP_ReadEntry(jzfile *zip, jzentry *entry, unsigned char *buf, char *entryname)
1588 {
1589 char *msg;
1590 char tmpbuf[1024];
1591
1592 if (entry == 0) {
1593 jio_fprintf(stderr, "jzentry was invalid");
1594 return JNI_FALSE;
1595 }
1596
1597 strcpy(entryname, entry->name);
1598 if (entry->csize == 0) {
1599 /* Entry is stored */
1600 jlong pos = 0;
1601 jlong size = entry->size;
1602 while (pos < size) {
1603 jint n;
1604 jlong limit = ((((jlong) 1) << 31) - 1);
1605 jint count = (size - pos < limit) ?
1606 /* These casts suppress a VC++ Internal Compiler Error */
1607 (jint) (size - pos) :
1608 (jint) limit;
1609 ZIP_Lock(zip);
1610 n = ZIP_Read(zip, entry, pos, buf, count);
1611 msg = zip->msg;
1612 ZIP_Unlock(zip);
1613 if (n == -1) {
1614 if (msg == 0) {
1615 getErrorString(errno, tmpbuf, sizeof(tmpbuf));
1616 msg = tmpbuf;
1617 }
1618 jio_fprintf(stderr, "%s: %s\n", zip->name, msg);
1619 return JNI_FALSE;
1620 }
1621 buf += n;
1622 pos += n;
1623 }
1624 } else {
1625 /* Entry is compressed */
1626 int ok = InflateFully(zip, entry, buf, &msg);
1627 if (!ok) {
1628 if ((msg == NULL) || (*msg == 0)) {
1629 msg = zip->msg;
1630 }
1631 if (msg == 0) {
1632 getErrorString(errno, tmpbuf, sizeof(tmpbuf));
1633 msg = tmpbuf;
1634 }
1635 jio_fprintf(stderr, "%s: %s\n", zip->name, msg);
1636 return JNI_FALSE;
1637 }
1638 }
1639
1640 ZIP_FreeEntry(zip, entry);
1641
1642 return JNI_TRUE;
1643 }
1644
1645 // BEGIN Android-added: Use strict mode to validate zip entry name.
1646 jboolean
ZIP_OnZipEntryAccess(JNIEnv * env,jobject thiz,const char * entryName,int len,jint flag)1647 ZIP_OnZipEntryAccess(JNIEnv *env, jobject thiz, const char* entryName, int len, jint flag) {
1648 jbyteArray array = (*env)->NewByteArray(env, len);
1649 (*env)->SetByteArrayRegion(env, array, 0, len, (jbyte*) entryName);
1650 (*env)->CallVoidMethod(env, thiz, jzOnZipEntryAccessID, array, flag);
1651 if ((*env)->ExceptionCheck(env)) {
1652 (*env)->ExceptionClear(env);
1653 return true;
1654 }
1655 return false;
1656 }
1657 // END Android-added: Use strict mode to validate zip entry name.
1658
1659 // BEGIN Android-removed: following methods are used outside of java.util.zip and
1660 // that code is absent from Android.
1661 /*
1662 JNIEXPORT jboolean
1663 ZIP_InflateFully(void *inBuf, jlong inLen, void *outBuf, jlong outLen, char **pmsg)
1664 {
1665 z_stream strm;
1666 int i = 0;
1667 memset(&strm, 0, sizeof(z_stream));
1668
1669 *pmsg = 0; * Reset error message *
1670
1671 if (inflateInit2(&strm, MAX_WBITS) != Z_OK) {
1672 *pmsg = strm.msg;
1673 return JNI_FALSE;
1674 }
1675
1676 strm.next_out = (Bytef *) outBuf;
1677 strm.avail_out = (uInt)outLen;
1678 strm.next_in = (Bytef *) inBuf;
1679 strm.avail_in = (uInt)inLen;
1680
1681 do {
1682 switch (inflate(&strm, Z_PARTIAL_FLUSH)) {
1683 case Z_OK:
1684 break;
1685 case Z_STREAM_END:
1686 if (strm.total_out != (uInt)outLen) {
1687 *pmsg = "INFLATER_inflateFully: Unexpected end of stream";
1688 inflateEnd(&strm);
1689 return JNI_FALSE;
1690 }
1691 break;
1692 case Z_DATA_ERROR:
1693 *pmsg = "INFLATER_inflateFully: Compressed data corrupted";
1694 inflateEnd(&strm);
1695 return JNI_FALSE;
1696 case Z_MEM_ERROR:
1697 *pmsg = "INFLATER_inflateFully: out of memory";
1698 inflateEnd(&strm);
1699 return JNI_FALSE;
1700 default:
1701 *pmsg = "INFLATER_inflateFully: internal error";
1702 inflateEnd(&strm);
1703 return JNI_FALSE;
1704 }
1705 } while (strm.avail_in > 0);
1706
1707 inflateEnd(&strm);
1708 return JNI_TRUE;
1709 }
1710
1711 static voidpf tracking_zlib_alloc(voidpf opaque, uInt items, uInt size) {
1712 size_t* needed = (size_t*) opaque;
1713 *needed += (size_t) items * (size_t) size;
1714 return (voidpf) calloc((size_t) items, (size_t) size);
1715 }
1716
1717 static void tracking_zlib_free(voidpf opaque, voidpf address) {
1718 free((void*) address);
1719 }
1720
1721 static voidpf zlib_block_alloc(voidpf opaque, uInt items, uInt size) {
1722 char** range = (char**) opaque;
1723 voidpf result = NULL;
1724 size_t needed = (size_t) items * (size_t) size;
1725
1726 if (range[1] - range[0] >= (ptrdiff_t) needed) {
1727 result = (voidpf) range[0];
1728 range[0] += needed;
1729 }
1730
1731 return result;
1732 }
1733
1734 static void zlib_block_free(voidpf opaque, voidpf address) {
1735 * Nothing to do. *
1736 }
1737
1738 static char const* deflateInit2Wrapper(z_stream* strm, int level) {
1739 int err = deflateInit2(strm, level >= 0 && level <= 9 ? level : Z_DEFAULT_COMPRESSION,
1740 Z_DEFLATED, 31, 8, Z_DEFAULT_STRATEGY);
1741 if (err == Z_MEM_ERROR) {
1742 return "Out of memory in deflateInit2";
1743 }
1744
1745 if (err != Z_OK) {
1746 return "Internal error in deflateInit2";
1747 }
1748
1749 return NULL;
1750 }
1751
1752 JNIEXPORT char const*
1753 ZIP_GZip_InitParams(size_t inLen, size_t* outLen, size_t* tmpLen, int level) {
1754 z_stream strm;
1755 *tmpLen = 0;
1756 char const* errorMsg;
1757
1758 memset(&strm, 0, sizeof(z_stream));
1759 strm.zalloc = tracking_zlib_alloc;
1760 strm.zfree = tracking_zlib_free;
1761 strm.opaque = (voidpf) tmpLen;
1762
1763 errorMsg = deflateInit2Wrapper(&strm, level);
1764
1765 if (errorMsg == NULL) {
1766 *outLen = (size_t) deflateBound(&strm, (uLong) inLen);
1767 deflateEnd(&strm);
1768 }
1769
1770 return errorMsg;
1771 }
1772
1773 JNIEXPORT size_t
1774 ZIP_GZip_Fully(char* inBuf, size_t inLen, char* outBuf, size_t outLen, char* tmp, size_t tmpLen,
1775 int level, char* comment, char const** pmsg) {
1776 z_stream strm;
1777 gz_header hdr;
1778 int err;
1779 char* block[] = {tmp, tmpLen + tmp};
1780 size_t result = 0;
1781
1782 memset(&strm, 0, sizeof(z_stream));
1783 strm.zalloc = zlib_block_alloc;
1784 strm.zfree = zlib_block_free;
1785 strm.opaque = (voidpf) block;
1786
1787 *pmsg = deflateInit2Wrapper(&strm, level);
1788
1789 if (*pmsg == NULL) {
1790 strm.next_out = (Bytef *) outBuf;
1791 strm.avail_out = (uInt) outLen;
1792 strm.next_in = (Bytef *) inBuf;
1793 strm.avail_in = (uInt) inLen;
1794
1795 if (comment != NULL) {
1796 memset(&hdr, 0, sizeof(hdr));
1797 hdr.comment = (Bytef*) comment;
1798 deflateSetHeader(&strm, &hdr);
1799 }
1800
1801 err = deflate(&strm, Z_FINISH);
1802
1803 if (err == Z_OK || err == Z_BUF_ERROR) {
1804 *pmsg = "Buffer too small";
1805 } else if (err != Z_STREAM_END) {
1806 *pmsg = "Intern deflate error";
1807 } else {
1808 result = (size_t) strm.total_out;
1809 }
1810
1811 deflateEnd(&strm);
1812 }
1813
1814 return result;
1815 }
1816 */
1817 // END Android-removed: following methods are used outside of java.util.zip and
1818 // that code is absent from Android.
1819