blob: bc6f51fe296115b5f4fc58ccdc91fda2fd9b4f69 [file] [log] [blame]
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001/*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17/*
18 * Byte-swapping and verification of dex files.
19 */
20
21#include "DexFile.h"
22#include "DexClass.h"
23#include "DexDataMap.h"
24#include "DexProto.h"
25#include "Leb128.h"
26
27#include <safe_iop.h>
28#include <zlib.h>
29
30#include <stdlib.h>
31#include <string.h>
32
33#ifndef __BYTE_ORDER
34# error "byte ordering not defined"
35#endif
36
37#if __BYTE_ORDER == __LITTLE_ENDIAN
38# define SWAP2(_value) (_value)
39# define SWAP4(_value) (_value)
40# define SWAP8(_value) (_value)
41#else
42# define SWAP2(_value) endianSwapU2((_value))
43# define SWAP4(_value) endianSwapU4((_value))
44# define SWAP8(_value) endianSwapU8((_value))
45static u2 endianSwapU2(u2 value) {
46 return (value >> 8) | (value << 8);
47}
48static u4 endianSwapU4(u4 value) {
49 /* ABCD --> CDAB --> DCBA */
50 value = (value >> 16) | (value << 16);
51 return ((value & 0xff00ff00) >> 8) | ((value << 8) & 0xff00ff00);
52}
53static u8 endianSwapU8(u8 value) {
54 /* ABCDEFGH --> EFGHABCD --> GHEFCDAB --> HGFEDCBA */
55 value = (value >> 32) | (value << 32);
56 value = ((value & 0xffff0000ffff0000ULL) >> 16) |
57 ((value << 16) & 0xffff0000ffff0000ULL);
58 return ((value & 0xff00ff00ff00ff00ULL) >> 8) |
59 ((value << 8) & 0xff00ff00ff00ff00ULL);
60}
61#endif
62
63#define SWAP_FIELD2(_field) (_field) = SWAP2(_field)
64#define SWAP_FIELD4(_field) (_field) = SWAP4(_field)
65#define SWAP_FIELD8(_field) (_field) = SWAP8(_field)
66
67/*
68 * Some information we pass around to help verify values.
69 */
70typedef struct CheckState {
71 const DexHeader* pHeader;
72 const u1* fileStart;
73 const u1* fileEnd; // points to fileStart + fileLen
74 u4 fileLen;
75 DexDataMap* pDataMap; // set after map verification
76 const DexFile* pDexFile; // set after intraitem verification
77 const void* previousItem; // set during section iteration
78} CheckState;
79
80/*
81 * Return the file offset of the given pointer.
82 */
83static inline u4 fileOffset(const CheckState* state, const void* ptr) {
84 return ((const u1*) ptr) - state->fileStart;
85}
86
87/*
88 * Return a pointer for the given file offset.
89 */
90static inline void* filePointer(const CheckState* state, u4 offset) {
91 return (void*) (state->fileStart + offset);
92}
93
94/*
95 * Verify that a pointer range, start inclusive to end exclusive, only
96 * covers bytes in the file and doesn't point beyond the end of the
97 * file. That is, the start must indicate a valid byte or may point at
98 * the byte just past the end of the file (but no further), and the
99 * end must be no less than the start and must also not point beyond
100 * the byte just past the end of the file.
101 */
102static inline bool checkPtrRange(const CheckState* state,
103 const void* start, const void* end, const char* label) {
104 const void* fileStart = state->fileStart;
105 const void* fileEnd = state->fileEnd;
106 if ((start < fileStart) || (start > fileEnd)
107 || (end < start) || (end > fileEnd)) {
108 LOGW("Bad offset range for %s: 0x%x..0x%x\n", label,
109 fileOffset(state, start), fileOffset(state, end));
110 return false;
111 }
112 return true;
113}
114
115/*
116 * Verify that a range of offsets, start inclusive to end exclusive,
117 * are all valid. That is, the start must indicate a valid byte or may
118 * point at the byte just past the end of the file (but no further),
119 * and the end must be no less than the start and must also not point
120 * beyond the byte just past the end of the file.
121 *
122 * Assumes "const CheckState* state".
123 */
124#define CHECK_OFFSET_RANGE(_start, _end) { \
125 const u1* _startPtr = filePointer(state, (_start)); \
126 const u1* _endPtr = filePointer(state, (_end)); \
127 if (!checkPtrRange(state, _startPtr, _endPtr, \
128 #_start ".." #_end)) { \
129 return 0; \
130 } \
131 }
132
133/*
134 * Verify that a pointer range, start inclusive to end exclusive, only
135 * covers bytes in the file and doesn't point beyond the end of the
136 * file. That is, the start must indicate a valid byte or may point at
137 * the byte just past the end of the file (but no further), and the
138 * end must be no less than the start and must also not point beyond
139 * the byte just past the end of the file.
140 *
141 * Assumes "const CheckState* state".
142 */
143#define CHECK_PTR_RANGE(_start, _end) { \
144 if (!checkPtrRange(state, (_start), (_end), #_start ".." #_end)) { \
145 return 0; \
146 } \
147 }
148
149/*
150 * Make sure a list of items fits entirely within the file.
151 *
152 * Assumes "const CheckState* state" and "typeof(_count) == typeof(_elemSize)"
153 * If the type sizes or signs are mismatched, this will return 0.
154 */
155#define CHECK_LIST_SIZE(_ptr, _count, _elemSize) { \
156 const u1* _start = (const u1*) (_ptr); \
157 const u1* _end = _start + ((_count) * (_elemSize)); \
158 if (!safe_mul(NULL, (_count), (_elemSize)) || \
159 !checkPtrRange(state, _start, _end, #_ptr)) { \
160 return 0; \
161 } \
162 }
163
164/*
165 * Swap a field that is known to hold an absolute DEX file offset. Note:
166 * This does not check to see that the swapped offset points within the
167 * mapped file, since that should be handled (with even more rigor) by
168 * the cross-verification phase.
169 *
170 * Assumes "const CheckState* state".
171 */
172#define SWAP_OFFSET4(_field) { \
173 SWAP_FIELD4((_field)); \
174 }
175
176/*
177 * Verify that an index falls in a valid range.
178 */
179#define CHECK_INDEX(_field, _limit) { \
180 if ((_field) >= (_limit)) { \
181 LOGW("Bad index: %s(%u) > %s(%u)\n", \
182 #_field, (u4)(_field), #_limit, (u4)(_limit)); \
183 return 0; \
184 } \
185 }
186
187/*
188 * Swap an index, and verify that it falls in a valid range.
189 */
190#define SWAP_INDEX2(_field, _limit) { \
191 SWAP_FIELD2((_field)); \
192 CHECK_INDEX((_field), (_limit)); \
193 }
194
195/*
196 * Verify that an index falls in a valid range or is kDexNoIndex.
197 */
198#define CHECK_INDEX_OR_NOINDEX(_field, _limit) { \
199 if ((_field) != kDexNoIndex && (_field) >= (_limit)) { \
200 LOGW("Bad index: %s(%u) > %s(%u)\n", \
201 #_field, (u4)(_field), #_limit, (u4)(_limit)); \
202 return 0; \
203 } \
204 }
205
206/*
207 * Swap an index, and verify that it falls in a valid range.
208 */
209#define SWAP_INDEX4(_field, _limit) { \
210 SWAP_FIELD4((_field)); \
211 CHECK_INDEX((_field), (_limit)); \
212 }
213
214/*
215 * Swap an index, and verify that it falls in a valid range or is
216 * kDexNoIndex.
217 */
218#define SWAP_INDEX4_OR_NOINDEX(_field, _limit) { \
219 SWAP_FIELD4((_field)); \
220 CHECK_INDEX_OR_NOINDEX((_field), (_limit)); \
221 }
222
223/* Verify the definer of a given field_idx. */
224static bool verifyFieldDefiner(const CheckState* state, u4 definingClass,
225 u4 fieldIdx) {
226 const DexFieldId* field = dexGetFieldId(state->pDexFile, fieldIdx);
227 return field->classIdx == definingClass;
228}
229
230/* Verify the definer of a given method_idx. */
231static bool verifyMethodDefiner(const CheckState* state, u4 definingClass,
232 u4 methodIdx) {
233 const DexMethodId* meth = dexGetMethodId(state->pDexFile, methodIdx);
234 return meth->classIdx == definingClass;
235}
236
237/*
238 * Swap the header_item.
239 */
240static bool swapDexHeader(const CheckState* state, DexHeader* pHeader)
241{
242 CHECK_PTR_RANGE(pHeader, pHeader + 1);
243
244 // magic is ok
245 SWAP_FIELD4(pHeader->checksum);
246 // signature is ok
247 SWAP_FIELD4(pHeader->fileSize);
248 SWAP_FIELD4(pHeader->headerSize);
249 SWAP_FIELD4(pHeader->endianTag);
250 SWAP_FIELD4(pHeader->linkSize);
251 SWAP_OFFSET4(pHeader->linkOff);
252 SWAP_OFFSET4(pHeader->mapOff);
253 SWAP_FIELD4(pHeader->stringIdsSize);
254 SWAP_OFFSET4(pHeader->stringIdsOff);
255 SWAP_FIELD4(pHeader->typeIdsSize);
256 SWAP_OFFSET4(pHeader->typeIdsOff);
257 SWAP_FIELD4(pHeader->fieldIdsSize);
258 SWAP_OFFSET4(pHeader->fieldIdsOff);
259 SWAP_FIELD4(pHeader->methodIdsSize);
260 SWAP_OFFSET4(pHeader->methodIdsOff);
261 SWAP_FIELD4(pHeader->protoIdsSize);
262 SWAP_OFFSET4(pHeader->protoIdsOff);
263 SWAP_FIELD4(pHeader->classDefsSize);
264 SWAP_OFFSET4(pHeader->classDefsOff);
265 SWAP_FIELD4(pHeader->dataSize);
266 SWAP_OFFSET4(pHeader->dataOff);
267
268 if (pHeader->endianTag != kDexEndianConstant) {
269 LOGE("Unexpected endian_tag: 0x%x\n", pHeader->endianTag);
270 return false;
271 }
272
273 // Assign variables so the diagnostic is prettier. (Hooray for macros.)
274 u4 linkOff = pHeader->linkOff;
275 u4 linkEnd = linkOff + pHeader->linkSize;
276 u4 dataOff = pHeader->dataOff;
277 u4 dataEnd = dataOff + pHeader->dataSize;
278 CHECK_OFFSET_RANGE(linkOff, linkEnd);
279 CHECK_OFFSET_RANGE(dataOff, dataEnd);
280
281 /*
282 * Note: The offsets and ranges of the other header items end up getting
283 * checked during the first iteration over the map.
284 */
285
286 return true;
287}
288
289/* Check the header section for sanity. */
290static bool checkHeaderSection(const CheckState* state, u4 sectionOffset,
291 u4 sectionCount, u4* endOffset) {
292 if (sectionCount != 1) {
293 LOGE("Multiple header items\n");
294 return false;
295 }
296
297 if (sectionOffset != 0) {
298 LOGE("Header at 0x%x; not at start of file\n", sectionOffset);
299 return false;
300 }
301
302 const DexHeader* pHeader = filePointer(state, 0);
303 *endOffset = pHeader->headerSize;
304 return true;
305}
306
307/*
308 * Helper for swapMap(), which turns a map type constant into a small
309 * one-bit-on integer, suitable for use in an int-sized bit set.
310 */
311static u4 mapTypeToBitMask(int mapType) {
312 switch (mapType) {
313 case kDexTypeHeaderItem: return 1 << 0;
314 case kDexTypeStringIdItem: return 1 << 1;
315 case kDexTypeTypeIdItem: return 1 << 2;
316 case kDexTypeProtoIdItem: return 1 << 3;
317 case kDexTypeFieldIdItem: return 1 << 4;
318 case kDexTypeMethodIdItem: return 1 << 5;
319 case kDexTypeClassDefItem: return 1 << 6;
320 case kDexTypeMapList: return 1 << 7;
321 case kDexTypeTypeList: return 1 << 8;
322 case kDexTypeAnnotationSetRefList: return 1 << 9;
323 case kDexTypeAnnotationSetItem: return 1 << 10;
324 case kDexTypeClassDataItem: return 1 << 11;
325 case kDexTypeCodeItem: return 1 << 12;
326 case kDexTypeStringDataItem: return 1 << 13;
327 case kDexTypeDebugInfoItem: return 1 << 14;
328 case kDexTypeAnnotationItem: return 1 << 15;
329 case kDexTypeEncodedArrayItem: return 1 << 16;
330 case kDexTypeAnnotationsDirectoryItem: return 1 << 17;
331 default: {
332 LOGE("Unknown map item type %04x\n", mapType);
333 return 0;
334 }
335 }
336}
337
338/*
339 * Helper for swapMap(), which indicates if an item type should appear
340 * in the data section.
341 */
342static bool isDataSectionType(int mapType) {
343 switch (mapType) {
344 case kDexTypeHeaderItem:
345 case kDexTypeStringIdItem:
346 case kDexTypeTypeIdItem:
347 case kDexTypeProtoIdItem:
348 case kDexTypeFieldIdItem:
349 case kDexTypeMethodIdItem:
350 case kDexTypeClassDefItem: {
351 return false;
352 }
353 }
354
355 return true;
356}
357
358/*
359 * Swap the map_list and verify what we can about it. Also, if verification
360 * passes, allocate the state's DexDataMap.
361 */
362static bool swapMap(CheckState* state, DexMapList* pMap)
363{
364 DexMapItem* item = pMap->list;
Andy McFaddene5058ef2009-03-30 12:56:53 -0700365 u4 count;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800366 u4 dataItemCount = 0; // Total count of items in the data section.
367 u4 dataItemsLeft = state->pHeader->dataSize; // See use below.
368 u4 usedBits = 0; // Bit set: one bit per section
369 bool first = true;
370 u4 lastOffset = 0;
Andy McFaddene5058ef2009-03-30 12:56:53 -0700371
372 SWAP_FIELD4(pMap->size);
373 count = pMap->size;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800374
375 CHECK_LIST_SIZE(item, count, sizeof(DexMapItem));
376
377 while (count--) {
378 SWAP_FIELD2(item->type);
379 SWAP_FIELD2(item->unused);
380 SWAP_FIELD4(item->size);
381 SWAP_OFFSET4(item->offset);
382
383 if (first) {
384 first = false;
385 } else if (lastOffset >= item->offset) {
386 LOGE("Out-of-order map item: 0x%x then 0x%x\n",
387 lastOffset, item->offset);
388 return false;
389 }
390
391 if (item->offset >= state->pHeader->fileSize) {
392 LOGE("Map item after end of file: %x, size 0x%x\n",
393 item->offset, state->pHeader->fileSize);
394 return false;
395 }
396
397 if (isDataSectionType(item->type)) {
Andy McFaddene5058ef2009-03-30 12:56:53 -0700398 u4 icount = item->size;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800399
400 /*
401 * This sanity check on the data section items ensures that
402 * there are no more items than the number of bytes in
403 * the data section.
404 */
Andy McFaddene5058ef2009-03-30 12:56:53 -0700405 if (icount > dataItemsLeft) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800406 LOGE("Unrealistically many items in the data section: "
Andy McFaddene5058ef2009-03-30 12:56:53 -0700407 "at least %d\n", dataItemCount + icount);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800408 return false;
409 }
410
Andy McFaddene5058ef2009-03-30 12:56:53 -0700411 dataItemsLeft -= icount;
412 dataItemCount += icount;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800413 }
414
415 u4 bit = mapTypeToBitMask(item->type);
416
417 if (bit == 0) {
418 return false;
419 }
420
421 if ((usedBits & bit) != 0) {
422 LOGE("Duplicate map section of type 0x%x\n", item->type);
423 return false;
424 }
425
426 usedBits |= bit;
427 lastOffset = item->offset;
428 item++;
429 }
430
431 if ((usedBits & mapTypeToBitMask(kDexTypeHeaderItem)) == 0) {
432 LOGE("Map is missing header entry\n");
433 return false;
434 }
435
436 if ((usedBits & mapTypeToBitMask(kDexTypeMapList)) == 0) {
437 LOGE("Map is missing map_list entry\n");
438 return false;
439 }
440
441 if (((usedBits & mapTypeToBitMask(kDexTypeStringIdItem)) == 0)
442 && ((state->pHeader->stringIdsOff != 0)
443 || (state->pHeader->stringIdsSize != 0))) {
444 LOGE("Map is missing string_ids entry\n");
445 return false;
446 }
447
448 if (((usedBits & mapTypeToBitMask(kDexTypeTypeIdItem)) == 0)
449 && ((state->pHeader->typeIdsOff != 0)
450 || (state->pHeader->typeIdsSize != 0))) {
451 LOGE("Map is missing type_ids entry\n");
452 return false;
453 }
454
455 if (((usedBits & mapTypeToBitMask(kDexTypeProtoIdItem)) == 0)
456 && ((state->pHeader->protoIdsOff != 0)
457 || (state->pHeader->protoIdsSize != 0))) {
458 LOGE("Map is missing proto_ids entry\n");
459 return false;
460 }
461
462 if (((usedBits & mapTypeToBitMask(kDexTypeFieldIdItem)) == 0)
463 && ((state->pHeader->fieldIdsOff != 0)
464 || (state->pHeader->fieldIdsSize != 0))) {
465 LOGE("Map is missing field_ids entry\n");
466 return false;
467 }
468
469 if (((usedBits & mapTypeToBitMask(kDexTypeMethodIdItem)) == 0)
470 && ((state->pHeader->methodIdsOff != 0)
471 || (state->pHeader->methodIdsSize != 0))) {
472 LOGE("Map is missing method_ids entry\n");
473 return false;
474 }
475
476 if (((usedBits & mapTypeToBitMask(kDexTypeClassDefItem)) == 0)
477 && ((state->pHeader->classDefsOff != 0)
478 || (state->pHeader->classDefsSize != 0))) {
479 LOGE("Map is missing class_defs entry\n");
480 return false;
481 }
482
483 state->pDataMap = dexDataMapAlloc(dataItemCount);
484 if (state->pDataMap == NULL) {
485 LOGE("Unable to allocate data map (size 0x%x)\n", dataItemCount);
486 return false;
487 }
488
489 return true;
490}
491
492/* Check the map section for sanity. */
493static bool checkMapSection(const CheckState* state, u4 sectionOffset,
494 u4 sectionCount, u4* endOffset) {
495 if (sectionCount != 1) {
496 LOGE("Multiple map list items");
497 return false;
498 }
499
500 if (sectionOffset != state->pHeader->mapOff) {
501 LOGE("Map not at header-defined offset: 0x%x, expected 0x%x\n",
502 sectionOffset, state->pHeader->mapOff);
503 return false;
504 }
505
506 const DexMapList* pMap = filePointer(state, sectionOffset);
507
508 *endOffset =
509 sectionOffset + sizeof(u4) + (pMap->size * sizeof(DexMapItem));
510 return true;
511}
512
513/* Perform byte-swapping and intra-item verification on string_id_item. */
514static void* swapStringIdItem(const CheckState* state, void* ptr) {
515 DexStringId* item = ptr;
516
517 CHECK_PTR_RANGE(item, item + 1);
518 SWAP_OFFSET4(item->stringDataOff);
519
520 return item + 1;
521}
522
523/* Perform cross-item verification of string_id_item. */
524static void* crossVerifyStringIdItem(const CheckState* state, void* ptr) {
525 const DexStringId* item = ptr;
526
527 if (!dexDataMapVerify(state->pDataMap,
528 item->stringDataOff, kDexTypeStringDataItem)) {
529 return NULL;
530 }
531
532 const DexStringId* item0 = state->previousItem;
533 if (item0 != NULL) {
534 // Check ordering.
535 const char* s0 = dexGetStringData(state->pDexFile, item0);
536 const char* s1 = dexGetStringData(state->pDexFile, item);
537 if (dexUtf8Cmp(s0, s1) >= 0) {
538 LOGE("Out-of-order string_ids: '%s' then '%s'\n", s0, s1);
539 return NULL;
540 }
541 }
542
543 return (void*) (item + 1);
544}
545
546/* Perform byte-swapping and intra-item verification on type_id_item. */
547static void* swapTypeIdItem(const CheckState* state, void* ptr) {
548 DexTypeId* item = ptr;
549
550 CHECK_PTR_RANGE(item, item + 1);
551 SWAP_INDEX4(item->descriptorIdx, state->pHeader->stringIdsSize);
552
553 return item + 1;
554}
555
556/* Perform cross-item verification of type_id_item. */
557static void* crossVerifyTypeIdItem(const CheckState* state, void* ptr) {
558 const DexTypeId* item = ptr;
559 const char* descriptor =
560 dexStringById(state->pDexFile, item->descriptorIdx);
561
562 if (!dexIsValidTypeDescriptor(descriptor)) {
563 LOGE("Invalid type descriptor: '%s'\n", descriptor);
564 return NULL;
565 }
566
567 const DexTypeId* item0 = state->previousItem;
568 if (item0 != NULL) {
569 // Check ordering. This relies on string_ids being in order.
570 if (item0->descriptorIdx >= item->descriptorIdx) {
571 LOGE("Out-of-order type_ids: 0x%x then 0x%x\n",
572 item0->descriptorIdx, item->descriptorIdx);
573 return NULL;
574 }
575 }
576
577 return (void*) (item + 1);
578}
579
580/* Perform byte-swapping and intra-item verification on proto_id_item. */
581static void* swapProtoIdItem(const CheckState* state, void* ptr) {
582 DexProtoId* item = ptr;
583
584 CHECK_PTR_RANGE(item, item + 1);
585 SWAP_INDEX4(item->shortyIdx, state->pHeader->stringIdsSize);
586 SWAP_INDEX4(item->returnTypeIdx, state->pHeader->typeIdsSize);
587 SWAP_OFFSET4(item->parametersOff);
588
589 return item + 1;
590}
591
592/* Helper for crossVerifyProtoIdItem(), which checks a shorty character
593 * to see if it is compatible with a type descriptor. Returns true if
594 * so, false if not. */
595static bool shortyDescMatch(char shorty, const char* descriptor, bool
596 isReturnType) {
597 switch (shorty) {
598 case 'V': {
599 if (!isReturnType) {
600 LOGE("Invalid use of void\n");
601 return false;
602 }
603 // Fall through.
604 }
605 case 'B':
606 case 'C':
607 case 'D':
608 case 'F':
609 case 'I':
610 case 'J':
611 case 'S':
612 case 'Z': {
613 if ((descriptor[0] != shorty) || (descriptor[1] != '\0')) {
614 LOGE("Shorty vs. primitive type mismatch: '%c', '%s'\n",
615 shorty, descriptor);
616 return false;
617 }
618 break;
619 }
620 case 'L': {
621 if ((descriptor[0] != 'L') && (descriptor[0] != '[')) {
622 LOGE("Shorty vs. type mismatch: '%c', '%s'\n",
623 shorty, descriptor);
624 return false;
625 }
626 break;
627 }
628 default: {
629 LOGE("Bogus shorty: '%c'\n", shorty);
630 return false;
631 }
632 }
633
634 return true;
635}
636
637/* Perform cross-item verification of proto_id_item. */
638static void* crossVerifyProtoIdItem(const CheckState* state, void* ptr) {
639 const DexProtoId* item = ptr;
640 const char* shorty =
641 dexStringById(state->pDexFile, item->shortyIdx);
642
643 if (!dexDataMapVerify0Ok(state->pDataMap,
644 item->parametersOff, kDexTypeTypeList)) {
645 return NULL;
646 }
647
648 if (!shortyDescMatch(*shorty,
649 dexStringByTypeIdx(state->pDexFile, item->returnTypeIdx),
650 true)) {
651 return NULL;
652 }
653
654 u4 protoIdx = item - state->pDexFile->pProtoIds;
655 DexProto proto = { state->pDexFile, protoIdx };
656 DexParameterIterator iterator;
657
658 dexParameterIteratorInit(&iterator, &proto);
659 shorty++; // Skip the return type.
660
661 for (;;) {
662 const char *desc = dexParameterIteratorNextDescriptor(&iterator);
663
664 if (desc == NULL) {
665 break;
666 }
667
668 if (*shorty == '\0') {
669 LOGE("Shorty is too short\n");
670 return NULL;
671 }
672
673 if (!shortyDescMatch(*shorty, desc, false)) {
674 return NULL;
675 }
676
677 shorty++;
678 }
679
680 if (*shorty != '\0') {
681 LOGE("Shorty is too long\n");
682 return NULL;
683 }
684
685 const DexProtoId* item0 = state->previousItem;
686 if (item0 != NULL) {
687 // Check ordering. This relies on type_ids being in order.
688 if (item0->returnTypeIdx > item->returnTypeIdx) {
689 LOGE("Out-of-order proto_id return types\n");
690 return NULL;
691 } else if (item0->returnTypeIdx == item->returnTypeIdx) {
692 bool badOrder = false;
693 DexProto proto0 = { state->pDexFile, protoIdx - 1 };
694 DexParameterIterator iterator0;
695
696 dexParameterIteratorInit(&iterator, &proto);
697 dexParameterIteratorInit(&iterator0, &proto0);
698
699 for (;;) {
700 u4 idx0 = dexParameterIteratorNextIndex(&iterator0);
701 u4 idx1 = dexParameterIteratorNextIndex(&iterator);
702
703 if (idx1 == kDexNoIndex) {
704 badOrder = true;
705 break;
706 }
707
708 if (idx0 == kDexNoIndex) {
709 break;
710 }
711
712 if (idx0 < idx1) {
713 break;
714 } else if (idx0 > idx1) {
715 badOrder = true;
716 break;
717 }
718 }
719
720 if (badOrder) {
721 LOGE("Out-of-order proto_id arguments\n");
722 return NULL;
723 }
724 }
725 }
726
727 return (void*) (item + 1);
728}
729
730/* Perform byte-swapping and intra-item verification on field_id_item. */
731static void* swapFieldIdItem(const CheckState* state, void* ptr) {
732 DexFieldId* item = ptr;
733
734 CHECK_PTR_RANGE(item, item + 1);
735 SWAP_INDEX2(item->classIdx, state->pHeader->typeIdsSize);
736 SWAP_INDEX2(item->typeIdx, state->pHeader->typeIdsSize);
737 SWAP_INDEX4(item->nameIdx, state->pHeader->stringIdsSize);
738
739 return item + 1;
740}
741
742/* Perform cross-item verification of field_id_item. */
743static void* crossVerifyFieldIdItem(const CheckState* state, void* ptr) {
744 const DexFieldId* item = ptr;
745 const char* s;
746
747 s = dexStringByTypeIdx(state->pDexFile, item->classIdx);
748 if (!dexIsClassDescriptor(s)) {
749 LOGE("Invalid descriptor for class_idx: '%s'\n", s);
750 return NULL;
751 }
752
753 s = dexStringByTypeIdx(state->pDexFile, item->typeIdx);
754 if (!dexIsFieldDescriptor(s)) {
755 LOGE("Invalid descriptor for type_idx: '%s'\n", s);
756 return NULL;
757 }
758
759 s = dexStringById(state->pDexFile, item->nameIdx);
760 if (!dexIsValidMemberName(s)) {
761 LOGE("Invalid name: '%s'\n", s);
762 return NULL;
763 }
764
765 const DexFieldId* item0 = state->previousItem;
766 if (item0 != NULL) {
767 // Check ordering. This relies on the other sections being in order.
768 bool done = false;
769 bool bogus = false;
770
771 if (item0->classIdx > item->classIdx) {
772 bogus = true;
773 done = true;
774 } else if (item0->classIdx < item->classIdx) {
775 done = true;
776 }
777
778 if (!done) {
779 if (item0->nameIdx > item->nameIdx) {
780 bogus = true;
781 done = true;
782 } else if (item0->nameIdx < item->nameIdx) {
783 done = true;
784 }
785 }
786
787 if (!done) {
788 if (item0->typeIdx >= item->typeIdx) {
789 bogus = true;
790 }
791 }
792
793 if (bogus) {
794 LOGE("Out-of-order field_ids\n");
795 return NULL;
796 }
797 }
798
799 return (void*) (item + 1);
800}
801
802/* Perform byte-swapping and intra-item verification on method_id_item. */
803static void* swapMethodIdItem(const CheckState* state, void* ptr) {
804 DexMethodId* item = ptr;
805
806 CHECK_PTR_RANGE(item, item + 1);
807 SWAP_INDEX2(item->classIdx, state->pHeader->typeIdsSize);
808 SWAP_INDEX2(item->protoIdx, state->pHeader->protoIdsSize);
809 SWAP_INDEX4(item->nameIdx, state->pHeader->stringIdsSize);
810
811 return item + 1;
812}
813
814/* Perform cross-item verification of method_id_item. */
815static void* crossVerifyMethodIdItem(const CheckState* state, void* ptr) {
816 const DexMethodId* item = ptr;
817 const char* s;
818
819 s = dexStringByTypeIdx(state->pDexFile, item->classIdx);
820 if (!dexIsReferenceDescriptor(s)) {
821 LOGE("Invalid descriptor for class_idx: '%s'\n", s);
822 return NULL;
823 }
824
825 s = dexStringById(state->pDexFile, item->nameIdx);
826 if (!dexIsValidMemberName(s)) {
827 LOGE("Invalid name: '%s'\n", s);
828 return NULL;
829 }
830
831 const DexMethodId* item0 = state->previousItem;
832 if (item0 != NULL) {
833 // Check ordering. This relies on the other sections being in order.
834 bool done = false;
835 bool bogus = false;
836
837 if (item0->classIdx > item->classIdx) {
838 bogus = true;
839 done = true;
840 } else if (item0->classIdx < item->classIdx) {
841 done = true;
842 }
843
844 if (!done) {
845 if (item0->nameIdx > item->nameIdx) {
846 bogus = true;
847 done = true;
848 } else if (item0->nameIdx < item->nameIdx) {
849 done = true;
850 }
851 }
852
853 if (!done) {
854 if (item0->protoIdx >= item->protoIdx) {
855 bogus = true;
856 }
857 }
858
859 if (bogus) {
860 LOGE("Out-of-order method_ids\n");
861 return NULL;
862 }
863 }
864
865 return (void*) (item + 1);
866}
867
868/* Perform byte-swapping and intra-item verification on class_def_item. */
869static void* swapClassDefItem(const CheckState* state, void* ptr) {
870 DexClassDef* item = ptr;
871
872 CHECK_PTR_RANGE(item, item + 1);
873 SWAP_INDEX4(item->classIdx, state->pHeader->typeIdsSize);
874 SWAP_FIELD4(item->accessFlags);
875 SWAP_INDEX4_OR_NOINDEX(item->superclassIdx, state->pHeader->typeIdsSize);
876 SWAP_OFFSET4(item->interfacesOff);
877 SWAP_INDEX4_OR_NOINDEX(item->sourceFileIdx, state->pHeader->stringIdsSize);
878 SWAP_OFFSET4(item->annotationsOff);
879 SWAP_OFFSET4(item->classDataOff);
880
881 return item + 1;
882}
883
884/* defined below */
885static u4 findFirstClassDataDefiner(const CheckState* state,
886 DexClassData* classData);
887static u4 findFirstAnnotationsDirectoryDefiner(const CheckState* state,
888 const DexAnnotationsDirectoryItem* dir);
889
890/* Helper for crossVerifyClassDefItem(), which checks a class_data_item to
891 * make sure all its references are to a given class. */
892static bool verifyClassDataIsForDef(const CheckState* state, u4 offset,
893 u4 definerIdx) {
894 if (offset == 0) {
895 return true;
896 }
897
898 const u1* data = filePointer(state, offset);
899 DexClassData* classData = dexReadAndVerifyClassData(&data, NULL);
900
901 if (classData == NULL) {
902 // Shouldn't happen, but bail here just in case.
903 return false;
904 }
905
906 /*
907 * The class_data_item verification ensures that
908 * it consistently refers to the same definer, so all we need to
909 * do is check the first one.
910 */
911 u4 dataDefiner = findFirstClassDataDefiner(state, classData);
912 bool result = (dataDefiner == definerIdx) || (dataDefiner == kDexNoIndex);
913
914 free(classData);
915 return result;
916}
917
918/* Helper for crossVerifyClassDefItem(), which checks an
919 * annotations_directory_item to make sure all its references are to a
920 * given class. */
921static bool verifyAnnotationsDirectoryIsForDef(const CheckState* state,
922 u4 offset, u4 definerIdx) {
923 if (offset == 0) {
924 return true;
925 }
926
927 const DexAnnotationsDirectoryItem* dir = filePointer(state, offset);
928 u4 annoDefiner = findFirstAnnotationsDirectoryDefiner(state, dir);
929
930 return (annoDefiner == definerIdx) || (annoDefiner == kDexNoIndex);
931}
932
933/* Perform cross-item verification of class_def_item. */
934static void* crossVerifyClassDefItem(const CheckState* state, void* ptr) {
935 const DexClassDef* item = ptr;
936 const char* descriptor =
937 dexStringByTypeIdx(state->pDexFile, item->classIdx);
938
939 if (!dexIsClassDescriptor(descriptor)) {
940 LOGE("Invalid class: '%s'\n", descriptor);
941 return NULL;
942 }
943
944 bool okay =
945 dexDataMapVerify0Ok(state->pDataMap,
946 item->interfacesOff, kDexTypeTypeList)
947 && dexDataMapVerify0Ok(state->pDataMap,
948 item->annotationsOff, kDexTypeAnnotationsDirectoryItem)
949 && dexDataMapVerify0Ok(state->pDataMap,
950 item->classDataOff, kDexTypeClassDataItem)
951 && dexDataMapVerify0Ok(state->pDataMap,
952 item->staticValuesOff, kDexTypeEncodedArrayItem);
953
954 if (!okay) {
955 return NULL;
956 }
957
958 if (item->superclassIdx != kDexNoIndex) {
959 descriptor = dexStringByTypeIdx(state->pDexFile, item->superclassIdx);
960 if (!dexIsClassDescriptor(descriptor)) {
961 LOGE("Invalid superclass: '%s'\n", descriptor);
962 return NULL;
963 }
964 }
965
966 const DexTypeList* interfaces =
967 dexGetInterfacesList(state->pDexFile, item);
968 if (interfaces != NULL) {
969 u4 size = interfaces->size;
970 u4 i;
971
972 /*
973 * Ensure that all interfaces refer to classes (not arrays or
974 * primitives).
975 */
976 for (i = 0; i < size; i++) {
977 descriptor = dexStringByTypeIdx(state->pDexFile,
978 dexTypeListGetIdx(interfaces, i));
979 if (!dexIsClassDescriptor(descriptor)) {
980 LOGE("Invalid interface: '%s'\n", descriptor);
981 return NULL;
982 }
983 }
984
985 /*
986 * Ensure that there are no duplicates. This is an O(N^2) test,
987 * but in practice the number of interfaces implemented by any
988 * given class is low. I will buy a milkshake for the
989 * first person to show me a realistic case for which this test
990 * would be unacceptably slow.
991 */
992 for (i = 1; i < size; i++) {
993 u4 idx1 = dexTypeListGetIdx(interfaces, i);
994 u4 j;
995 for (j = 0; j < i; j++) {
996 u4 idx2 = dexTypeListGetIdx(interfaces, j);
997 if (idx1 == idx2) {
998 LOGE("Duplicate interface: '%s'\n",
999 dexStringByTypeIdx(state->pDexFile, idx1));
1000 return NULL;
1001 }
1002 }
1003 }
1004 }
1005
1006 if (!verifyClassDataIsForDef(state, item->classDataOff, item->classIdx)) {
1007 LOGE("Invalid class_data_item\n");
1008 return NULL;
1009 }
1010
1011 if (!verifyAnnotationsDirectoryIsForDef(state, item->annotationsOff,
1012 item->classIdx)) {
1013 LOGE("Invalid annotations_directory_item\n");
1014 return NULL;
1015 }
1016
1017 return (void*) (item + 1);
1018}
1019
1020/* Helper for swapAnnotationsDirectoryItem(), which performs
1021 * byte-swapping and intra-item verification on an
1022 * annotation_directory_item's field elements. */
1023static u1* swapFieldAnnotations(const CheckState* state, u4 count, u1* addr) {
1024 DexFieldAnnotationsItem* item = (DexFieldAnnotationsItem*) addr;
1025 bool first = true;
1026 u4 lastIdx = 0;
1027
1028 CHECK_LIST_SIZE(item, count, sizeof(DexFieldAnnotationsItem));
1029
1030 while (count--) {
1031 SWAP_INDEX4(item->fieldIdx, state->pHeader->fieldIdsSize);
1032 SWAP_OFFSET4(item->annotationsOff);
1033
1034 if (first) {
1035 first = false;
1036 } else if (lastIdx >= item->fieldIdx) {
1037 LOGE("Out-of-order field_idx: 0x%x then 0x%x\n", lastIdx,
1038 item->fieldIdx);
1039 return NULL;
1040 }
1041
1042 lastIdx = item->fieldIdx;
1043 item++;
1044 }
1045
1046 return (u1*) item;
1047}
1048
1049/* Helper for swapAnnotationsDirectoryItem(), which performs
1050 * byte-swapping and intra-item verification on an
1051 * annotation_directory_item's method elements. */
1052static u1* swapMethodAnnotations(const CheckState* state, u4 count, u1* addr) {
1053 DexMethodAnnotationsItem* item = (DexMethodAnnotationsItem*) addr;
1054 bool first = true;
1055 u4 lastIdx = 0;
1056
1057 CHECK_LIST_SIZE(item, count, sizeof(DexMethodAnnotationsItem));
1058
1059 while (count--) {
1060 SWAP_INDEX4(item->methodIdx, state->pHeader->methodIdsSize);
1061 SWAP_OFFSET4(item->annotationsOff);
1062
1063 if (first) {
1064 first = false;
1065 } else if (lastIdx >= item->methodIdx) {
1066 LOGE("Out-of-order method_idx: 0x%x then 0x%x\n", lastIdx,
1067 item->methodIdx);
1068 return NULL;
1069 }
1070
1071 lastIdx = item->methodIdx;
1072 item++;
1073 }
1074
1075 return (u1*) item;
1076}
1077
1078/* Helper for swapAnnotationsDirectoryItem(), which performs
1079 * byte-swapping and intra-item verification on an
1080 * annotation_directory_item's parameter elements. */
1081static u1* swapParameterAnnotations(const CheckState* state, u4 count,
1082 u1* addr) {
1083 DexParameterAnnotationsItem* item = (DexParameterAnnotationsItem*) addr;
1084 bool first = true;
1085 u4 lastIdx = 0;
1086
1087 CHECK_LIST_SIZE(item, count, sizeof(DexParameterAnnotationsItem));
1088
1089 while (count--) {
1090 SWAP_INDEX4(item->methodIdx, state->pHeader->methodIdsSize);
1091 SWAP_OFFSET4(item->annotationsOff);
1092
1093 if (first) {
1094 first = false;
1095 } else if (lastIdx >= item->methodIdx) {
1096 LOGE("Out-of-order method_idx: 0x%x then 0x%x\n", lastIdx,
1097 item->methodIdx);
1098 return NULL;
1099 }
1100
1101 lastIdx = item->methodIdx;
1102 item++;
1103 }
1104
1105 return (u1*) item;
1106}
1107
1108/* Perform byte-swapping and intra-item verification on
1109 * annotations_directory_item. */
1110static void* swapAnnotationsDirectoryItem(const CheckState* state, void* ptr) {
1111 DexAnnotationsDirectoryItem* item = ptr;
1112
1113 CHECK_PTR_RANGE(item, item + 1);
1114 SWAP_OFFSET4(item->classAnnotationsOff);
1115 SWAP_FIELD4(item->fieldsSize);
1116 SWAP_FIELD4(item->methodsSize);
1117 SWAP_FIELD4(item->parametersSize);
1118
1119 u1* addr = (u1*) (item + 1);
1120
1121 if (item->fieldsSize != 0) {
1122 addr = swapFieldAnnotations(state, item->fieldsSize, addr);
1123 if (addr == NULL) {
1124 return NULL;
1125 }
1126 }
1127
1128 if (item->methodsSize != 0) {
1129 addr = swapMethodAnnotations(state, item->methodsSize, addr);
1130 if (addr == NULL) {
1131 return NULL;
1132 }
1133 }
1134
1135 if (item->parametersSize != 0) {
1136 addr = swapParameterAnnotations(state, item->parametersSize, addr);
1137 if (addr == NULL) {
1138 return NULL;
1139 }
1140 }
1141
1142 return addr;
1143}
1144
1145/* Helper for crossVerifyAnnotationsDirectoryItem(), which checks the
1146 * field elements. */
1147static const u1* crossVerifyFieldAnnotations(const CheckState* state, u4 count,
1148 const u1* addr, u4 definingClass) {
1149 const DexFieldAnnotationsItem* item = (DexFieldAnnotationsItem*) addr;
1150
1151 while (count--) {
1152 if (!verifyFieldDefiner(state, definingClass, item->fieldIdx)) {
1153 return NULL;
1154 }
1155 if (!dexDataMapVerify(state->pDataMap, item->annotationsOff,
1156 kDexTypeAnnotationSetItem)) {
1157 return NULL;
1158 }
1159 item++;
1160 }
1161
1162 return (const u1*) item;
1163}
1164
1165/* Helper for crossVerifyAnnotationsDirectoryItem(), which checks the
1166 * method elements. */
1167static const u1* crossVerifyMethodAnnotations(const CheckState* state,
1168 u4 count, const u1* addr, u4 definingClass) {
1169 const DexMethodAnnotationsItem* item = (DexMethodAnnotationsItem*) addr;
1170
1171 while (count--) {
1172 if (!verifyMethodDefiner(state, definingClass, item->methodIdx)) {
1173 return NULL;
1174 }
1175 if (!dexDataMapVerify(state->pDataMap, item->annotationsOff,
1176 kDexTypeAnnotationSetItem)) {
1177 return NULL;
1178 }
1179 item++;
1180 }
1181
1182 return (const u1*) item;
1183}
1184
1185/* Helper for crossVerifyAnnotationsDirectoryItem(), which checks the
1186 * parameter elements. */
1187static const u1* crossVerifyParameterAnnotations(const CheckState* state,
1188 u4 count, const u1* addr, u4 definingClass) {
1189 const DexParameterAnnotationsItem* item =
1190 (DexParameterAnnotationsItem*) addr;
1191
1192 while (count--) {
1193 if (!verifyMethodDefiner(state, definingClass, item->methodIdx)) {
1194 return NULL;
1195 }
1196 if (!dexDataMapVerify(state->pDataMap, item->annotationsOff,
1197 kDexTypeAnnotationSetRefList)) {
1198 return NULL;
1199 }
1200 item++;
1201 }
1202
1203 return (const u1*) item;
1204}
1205
1206/* Helper for crossVerifyClassDefItem() and
1207 * crossVerifyAnnotationsDirectoryItem(), which finds the type_idx of
1208 * the definer of the first item in the data. */
1209static u4 findFirstAnnotationsDirectoryDefiner(const CheckState* state,
1210 const DexAnnotationsDirectoryItem* dir) {
1211 if (dir->fieldsSize != 0) {
1212 const DexFieldAnnotationsItem* fields =
1213 dexGetFieldAnnotations(state->pDexFile, dir);
1214 const DexFieldId* field =
1215 dexGetFieldId(state->pDexFile, fields[0].fieldIdx);
1216 return field->classIdx;
1217 }
1218
1219 if (dir->methodsSize != 0) {
1220 const DexMethodAnnotationsItem* methods =
1221 dexGetMethodAnnotations(state->pDexFile, dir);
1222 const DexMethodId* method =
1223 dexGetMethodId(state->pDexFile, methods[0].methodIdx);
1224 return method->classIdx;
1225 }
1226
1227 if (dir->parametersSize != 0) {
1228 const DexParameterAnnotationsItem* parameters =
1229 dexGetParameterAnnotations(state->pDexFile, dir);
1230 const DexMethodId* method =
1231 dexGetMethodId(state->pDexFile, parameters[0].methodIdx);
1232 return method->classIdx;
1233 }
1234
1235 return kDexNoIndex;
1236}
1237
1238/* Perform cross-item verification of annotations_directory_item. */
1239static void* crossVerifyAnnotationsDirectoryItem(const CheckState* state,
1240 void* ptr) {
1241 const DexAnnotationsDirectoryItem* item = ptr;
1242 u4 definingClass = findFirstAnnotationsDirectoryDefiner(state, item);
1243
1244 if (!dexDataMapVerify0Ok(state->pDataMap,
1245 item->classAnnotationsOff, kDexTypeAnnotationSetItem)) {
1246 return NULL;
1247 }
1248
1249 const u1* addr = (const u1*) (item + 1);
1250
1251 if (item->fieldsSize != 0) {
1252 addr = crossVerifyFieldAnnotations(state, item->fieldsSize, addr,
1253 definingClass);
1254 if (addr == NULL) {
1255 return NULL;
1256 }
1257 }
1258
1259 if (item->methodsSize != 0) {
1260 addr = crossVerifyMethodAnnotations(state, item->methodsSize, addr,
1261 definingClass);
1262 if (addr == NULL) {
1263 return NULL;
1264 }
1265 }
1266
1267 if (item->parametersSize != 0) {
1268 addr = crossVerifyParameterAnnotations(state, item->parametersSize,
1269 addr, definingClass);
1270 if (addr == NULL) {
1271 return NULL;
1272 }
1273 }
1274
1275 return (void*) addr;
1276}
1277
1278/* Perform byte-swapping and intra-item verification on type_list. */
1279static void* swapTypeList(const CheckState* state, void* ptr)
1280{
1281 DexTypeList* pTypeList = ptr;
1282 DexTypeItem* pType;
1283 u4 count;
1284
1285 CHECK_PTR_RANGE(pTypeList, pTypeList + 1);
1286 SWAP_FIELD4(pTypeList->size);
1287 count = pTypeList->size;
1288 pType = pTypeList->list;
1289 CHECK_LIST_SIZE(pType, count, sizeof(DexTypeItem));
1290
1291 while (count--) {
1292 SWAP_INDEX2(pType->typeIdx, state->pHeader->typeIdsSize);
1293 pType++;
1294 }
1295
1296 return pType;
1297}
1298
1299/* Perform byte-swapping and intra-item verification on
1300 * annotation_set_ref_list. */
1301static void* swapAnnotationSetRefList(const CheckState* state, void* ptr) {
1302 DexAnnotationSetRefList* list = ptr;
1303 DexAnnotationSetRefItem* item;
1304 u4 count;
1305
1306 CHECK_PTR_RANGE(list, list + 1);
1307 SWAP_FIELD4(list->size);
1308 count = list->size;
1309 item = list->list;
1310 CHECK_LIST_SIZE(item, count, sizeof(DexAnnotationSetRefItem));
1311
1312 while (count--) {
1313 SWAP_OFFSET4(item->annotationsOff);
1314 item++;
1315 }
1316
1317 return item;
1318}
1319
1320/* Perform cross-item verification of annotation_set_ref_list. */
1321static void* crossVerifyAnnotationSetRefList(const CheckState* state,
1322 void* ptr) {
1323 const DexAnnotationSetRefList* list = ptr;
1324 const DexAnnotationSetRefItem* item = list->list;
1325 int count = list->size;
1326
1327 while (count--) {
1328 if (!dexDataMapVerify0Ok(state->pDataMap,
1329 item->annotationsOff, kDexTypeAnnotationSetItem)) {
1330 return NULL;
1331 }
1332 item++;
1333 }
1334
1335 return (void*) item;
1336}
1337
1338/* Perform byte-swapping and intra-item verification on
1339 * annotation_set_item. */
1340static void* swapAnnotationSetItem(const CheckState* state, void* ptr) {
1341 DexAnnotationSetItem* set = ptr;
1342 u4* item;
1343 u4 count;
1344
1345 CHECK_PTR_RANGE(set, set + 1);
1346 SWAP_FIELD4(set->size);
1347 count = set->size;
1348 item = set->entries;
1349 CHECK_LIST_SIZE(item, count, sizeof(u4));
1350
1351 while (count--) {
1352 SWAP_OFFSET4(*item);
1353 item++;
1354 }
1355
1356 return item;
1357}
1358
1359/* Helper for crossVerifyAnnotationSetItem(), which extracts the type_idx
1360 * out of an annotation_item. */
1361static u4 annotationItemTypeIdx(const DexAnnotationItem* item) {
1362 const u1* data = item->annotation;
1363 return readUnsignedLeb128(&data);
1364}
1365
1366/* Perform cross-item verification of annotation_set_item. */
1367static void* crossVerifyAnnotationSetItem(const CheckState* state, void* ptr) {
1368 const DexAnnotationSetItem* set = ptr;
1369 int count = set->size;
1370 u4 lastIdx = 0;
1371 bool first = true;
1372 int i;
1373
1374 for (i = 0; i < count; i++) {
1375 if (!dexDataMapVerify0Ok(state->pDataMap,
1376 dexGetAnnotationOff(set, i), kDexTypeAnnotationItem)) {
1377 return NULL;
1378 }
1379
1380 const DexAnnotationItem* annotation =
1381 dexGetAnnotationItem(state->pDexFile, set, i);
1382 u4 idx = annotationItemTypeIdx(annotation);
1383
1384 if (first) {
1385 first = false;
1386 } else if (lastIdx >= idx) {
1387 LOGE("Out-of-order entry types: 0x%x then 0x%x\n",
1388 lastIdx, idx);
1389 return NULL;
1390 }
1391
1392 lastIdx = idx;
1393 }
1394
1395 return (void*) (set->entries + count);
1396}
1397
1398/* Helper for verifyClassDataItem(), which checks a list of fields. */
1399static bool verifyFields(const CheckState* state, u4 size,
1400 DexField* fields, bool expectStatic) {
1401 u4 i;
1402
1403 for (i = 0; i < size; i++) {
1404 DexField* field = &fields[i];
1405 u4 accessFlags = field->accessFlags;
1406 bool isStatic = (accessFlags & ACC_STATIC) != 0;
1407
1408 CHECK_INDEX(field->fieldIdx, state->pHeader->fieldIdsSize);
1409
1410 if (isStatic != expectStatic) {
1411 LOGE("Field in wrong list @ %d\n", i);
1412 return false;
1413 }
1414
1415 if ((accessFlags & ~ACC_FIELD_MASK) != 0) {
1416 LOGE("Bogus field access flags %x @ %d\n", accessFlags, i);
1417 return false;
1418 }
1419 }
1420
1421 return true;
1422}
1423
1424/* Helper for verifyClassDataItem(), which checks a list of methods. */
1425static bool verifyMethods(const CheckState* state, u4 size,
1426 DexMethod* methods, bool expectDirect) {
1427 u4 i;
1428
1429 for (i = 0; i < size; i++) {
1430 DexMethod* method = &methods[i];
1431
1432 CHECK_INDEX(method->methodIdx, state->pHeader->methodIdsSize);
1433
1434 u4 accessFlags = method->accessFlags;
1435 bool isDirect =
1436 (accessFlags & (ACC_STATIC | ACC_PRIVATE | ACC_CONSTRUCTOR)) != 0;
1437 bool expectCode = (accessFlags & (ACC_NATIVE | ACC_ABSTRACT)) == 0;
1438 bool isSynchronized = (accessFlags & ACC_SYNCHRONIZED) != 0;
1439 bool allowSynchronized = (accessFlags & ACC_NATIVE) != 0;
1440
1441 if (isDirect != expectDirect) {
1442 LOGE("Method in wrong list @ %d\n", i);
1443 return false;
1444 }
1445
1446 if (((accessFlags & ~ACC_METHOD_MASK) != 0)
1447 || (isSynchronized && !allowSynchronized)) {
1448 LOGE("Bogus method access flags %x @ %d\n", accessFlags, i);
1449 return false;
1450 }
1451
1452 if (expectCode) {
1453 if (method->codeOff == 0) {
1454 LOGE("Unexpected zero code_off for access_flags %x\n",
1455 accessFlags);
1456 return false;
1457 }
1458 } else if (method->codeOff != 0) {
1459 LOGE("Unexpected non-zero code_off 0x%x for access_flags %x\n",
1460 method->codeOff, accessFlags);
1461 return false;
1462 }
1463 }
1464
1465 return true;
1466}
1467
1468/* Helper for verifyClassDataItem(), which does most of the work. */
1469static bool verifyClassDataItem0(const CheckState* state,
1470 DexClassData* classData) {
1471 bool okay;
1472
1473 okay = verifyFields(state, classData->header.staticFieldsSize,
1474 classData->staticFields, true);
1475
1476 if (!okay) {
1477 LOGE("Trouble with static fields\n");
1478 return false;
1479 }
1480
1481 verifyFields(state, classData->header.instanceFieldsSize,
1482 classData->instanceFields, false);
1483
1484 if (!okay) {
1485 LOGE("Trouble with instance fields\n");
1486 return false;
1487 }
1488
1489 okay = verifyMethods(state, classData->header.directMethodsSize,
1490 classData->directMethods, true);
1491
1492 if (!okay) {
1493 LOGE("Trouble with direct methods\n");
1494 return false;
1495 }
1496
1497 okay = verifyMethods(state, classData->header.virtualMethodsSize,
1498 classData->virtualMethods, false);
1499
1500 if (!okay) {
1501 LOGE("Trouble with virtual methods\n");
1502 return false;
1503 }
1504
1505 return true;
1506}
1507
1508/* Perform intra-item verification on class_data_item. */
1509static void* intraVerifyClassDataItem(const CheckState* state, void* ptr) {
1510 const u1* data = ptr;
1511 DexClassData* classData = dexReadAndVerifyClassData(&data, state->fileEnd);
1512
1513 if (classData == NULL) {
1514 LOGE("Unable to parse class_data_item\n");
1515 return NULL;
1516 }
1517
1518 bool okay = verifyClassDataItem0(state, classData);
1519
1520 free(classData);
1521
1522 if (!okay) {
1523 return NULL;
1524 }
1525
1526 return (void*) data;
1527}
1528
1529/* Helper for crossVerifyClassDefItem() and
1530 * crossVerifyClassDataItem(), which finds the type_idx of the definer
1531 * of the first item in the data. */
1532static u4 findFirstClassDataDefiner(const CheckState* state,
1533 DexClassData* classData) {
1534 if (classData->header.staticFieldsSize != 0) {
1535 u4 fieldIdx = classData->staticFields[0].fieldIdx;
1536 const DexFieldId* field = dexGetFieldId(state->pDexFile, fieldIdx);
1537 return field->classIdx;
1538 }
1539
1540 if (classData->header.instanceFieldsSize != 0) {
1541 u4 fieldIdx = classData->instanceFields[0].fieldIdx;
1542 const DexFieldId* field = dexGetFieldId(state->pDexFile, fieldIdx);
1543 return field->classIdx;
1544 }
1545
1546 if (classData->header.directMethodsSize != 0) {
1547 u4 methodIdx = classData->directMethods[0].methodIdx;
1548 const DexMethodId* meth = dexGetMethodId(state->pDexFile, methodIdx);
1549 return meth->classIdx;
1550 }
1551
1552 if (classData->header.virtualMethodsSize != 0) {
1553 u4 methodIdx = classData->virtualMethods[0].methodIdx;
1554 const DexMethodId* meth = dexGetMethodId(state->pDexFile, methodIdx);
1555 return meth->classIdx;
1556 }
1557
1558 return kDexNoIndex;
1559}
1560
1561/* Perform cross-item verification of class_data_item. */
1562static void* crossVerifyClassDataItem(const CheckState* state, void* ptr) {
1563 const u1* data = ptr;
1564 DexClassData* classData = dexReadAndVerifyClassData(&data, state->fileEnd);
1565 u4 definingClass = findFirstClassDataDefiner(state, classData);
1566 bool okay = true;
1567 u4 i;
1568
1569 for (i = classData->header.staticFieldsSize; okay && (i > 0); /*i*/) {
1570 i--;
1571 const DexField* field = &classData->staticFields[i];
1572 okay = verifyFieldDefiner(state, definingClass, field->fieldIdx);
1573 }
1574
1575 for (i = classData->header.instanceFieldsSize; okay && (i > 0); /*i*/) {
1576 i--;
1577 const DexField* field = &classData->instanceFields[i];
1578 okay = verifyFieldDefiner(state, definingClass, field->fieldIdx);
1579 }
1580
1581 for (i = classData->header.directMethodsSize; okay && (i > 0); /*i*/) {
1582 i--;
1583 const DexMethod* meth = &classData->directMethods[i];
1584 okay = dexDataMapVerify0Ok(state->pDataMap, meth->codeOff,
1585 kDexTypeCodeItem)
1586 && verifyMethodDefiner(state, definingClass, meth->methodIdx);
1587 }
1588
1589 for (i = classData->header.virtualMethodsSize; okay && (i > 0); /*i*/) {
1590 i--;
1591 const DexMethod* meth = &classData->virtualMethods[i];
1592 okay = dexDataMapVerify0Ok(state->pDataMap, meth->codeOff,
1593 kDexTypeCodeItem)
1594 && verifyMethodDefiner(state, definingClass, meth->methodIdx);
1595 }
1596
1597 free(classData);
1598
1599 if (!okay) {
1600 return NULL;
1601 }
1602
1603 return (void*) data;
1604}
1605
1606/* Helper for swapCodeItem(), which fills an array with all the valid
1607 * handlerOff values for catch handlers and also verifies the handler
1608 * contents. */
1609static u4 setHandlerOffsAndVerify(const CheckState* state,
1610 DexCode* code, u4 firstOffset, u4 handlersSize, u4* handlerOffs) {
1611 const u1* fileEnd = state->fileEnd;
1612 const u1* handlersBase = dexGetCatchHandlerData(code);
1613 u4 offset = firstOffset;
1614 bool okay = true;
1615 u4 i;
1616
1617 for (i = 0; i < handlersSize; i++) {
1618 const u1* ptr = handlersBase + offset;
1619 int size = readAndVerifySignedLeb128(&ptr, fileEnd, &okay);
1620 bool catchAll;
1621
1622 if (!okay) {
1623 LOGE("Bogus size\n");
1624 return 0;
1625 }
1626
1627 if ((size < -65536) || (size > 65536)) {
1628 LOGE("Invalid size: %d\n", size);
1629 return 0;
1630 }
1631
1632 if (size <= 0) {
1633 catchAll = true;
1634 size = -size;
1635 } else {
1636 catchAll = false;
1637 }
1638
1639 handlerOffs[i] = offset;
1640
1641 while (size-- > 0) {
1642 u4 typeIdx =
1643 readAndVerifyUnsignedLeb128(&ptr, fileEnd, &okay);
1644
1645 if (!okay) {
1646 LOGE("Bogus type_idx");
1647 return 0;
1648 }
1649
1650 CHECK_INDEX(typeIdx, state->pHeader->typeIdsSize);
1651
1652 u4 addr = readAndVerifyUnsignedLeb128(&ptr, fileEnd, &okay);
1653
1654 if (!okay) {
1655 LOGE("Bogus addr");
1656 return 0;
1657 }
1658
1659 if (addr >= code->insnsSize) {
1660 LOGE("Invalid addr: 0x%x", addr);
1661 return 0;
1662 }
1663 }
1664
1665 if (catchAll) {
1666 u4 addr = readAndVerifyUnsignedLeb128(&ptr, fileEnd, &okay);
1667
1668 if (!okay) {
1669 LOGE("Bogus catch_all_addr");
1670 return 0;
1671 }
1672
1673 if (addr >= code->insnsSize) {
1674 LOGE("Invalid catch_all_addr: 0x%x", addr);
1675 return 0;
1676 }
1677 }
1678
1679 offset = ptr - handlersBase;
1680 }
1681
1682 return offset;
1683}
1684
1685/* Helper for swapCodeItem(), which does all the try-catch related
1686 * swapping and verification. */
1687static void* swapTriesAndCatches(const CheckState* state, DexCode* code) {
1688 const u1* encodedHandlers = dexGetCatchHandlerData(code);
1689 const u1* encodedPtr = encodedHandlers;
1690 bool okay = true;
1691 u4 handlersSize =
1692 readAndVerifyUnsignedLeb128(&encodedPtr, state->fileEnd, &okay);
1693
1694 if (!okay) {
1695 LOGE("Bogus handlers_size\n");
1696 return NULL;
1697 }
1698
1699 if ((handlersSize == 0) || (handlersSize >= 65536)) {
1700 LOGE("Invalid handlers_size: %d\n", handlersSize);
1701 return NULL;
1702 }
1703
1704 u4 handlerOffs[handlersSize]; // list of valid handlerOff values
1705 u4 endOffset = setHandlerOffsAndVerify(state, code,
1706 encodedPtr - encodedHandlers,
1707 handlersSize, handlerOffs);
1708
1709 if (endOffset == 0) {
1710 return NULL;
1711 }
1712
1713 DexTry* tries = (DexTry*) dexGetTries(code);
1714 u4 count = code->triesSize;
1715 u4 lastEnd = 0;
1716
1717 CHECK_LIST_SIZE(tries, count, sizeof(DexTry));
1718
1719 while (count--) {
1720 u4 i;
1721
1722 SWAP_FIELD4(tries->startAddr);
1723 SWAP_FIELD2(tries->insnCount);
1724 SWAP_FIELD2(tries->handlerOff);
1725
1726 if (tries->startAddr < lastEnd) {
1727 LOGE("Out-of-order try\n");
1728 return NULL;
1729 }
1730
1731 if (tries->startAddr >= code->insnsSize) {
1732 LOGE("Invalid start_addr: 0x%x\n", tries->startAddr);
1733 return NULL;
1734 }
1735
1736 for (i = 0; i < handlersSize; i++) {
1737 if (tries->handlerOff == handlerOffs[i]) {
1738 break;
1739 }
1740 }
1741
1742 if (i == handlersSize) {
1743 LOGE("Bogus handler offset: 0x%x\n", tries->handlerOff);
1744 return NULL;
1745 }
1746
1747 lastEnd = tries->startAddr + tries->insnCount;
1748
1749 if (lastEnd > code->insnsSize) {
1750 LOGE("Invalid insn_count: 0x%x (end addr 0x%x)\n",
1751 tries->insnCount, lastEnd);
1752 return NULL;
1753 }
1754
1755 tries++;
1756 }
1757
1758 return (u1*) encodedHandlers + endOffset;
1759}
1760
1761/* Perform byte-swapping and intra-item verification on code_item. */
1762static void* swapCodeItem(const CheckState* state, void* ptr) {
1763 DexCode* item = ptr;
1764 u2* insns;
1765 u4 count;
1766
1767 CHECK_PTR_RANGE(item, item + 1);
1768 SWAP_FIELD2(item->registersSize);
1769 SWAP_FIELD2(item->insSize);
1770 SWAP_FIELD2(item->outsSize);
1771 SWAP_FIELD2(item->triesSize);
1772 SWAP_OFFSET4(item->debugInfoOff);
1773 SWAP_FIELD4(item->insnsSize);
1774
1775 count = item->insnsSize;
1776 insns = item->insns;
1777 CHECK_LIST_SIZE(insns, count, sizeof(u2));
1778
1779 while (count--) {
1780 *insns = SWAP2(*insns);
1781 insns++;
1782 }
1783
1784 if (item->triesSize == 0) {
1785 ptr = insns;
1786 } else {
1787 if ((((u4) insns) & 3) != 0) {
1788 // Four-byte alignment for the tries. Verify the spacer is a 0.
1789 if (*insns != 0) {
1790 LOGE("Non-zero padding: 0x%x\n", (u4) *insns);
1791 return NULL;
1792 }
1793 }
1794
1795 ptr = swapTriesAndCatches(state, item);
1796 }
1797
1798 return ptr;
1799}
1800
1801/* Perform intra-item verification on string_data_item. */
1802static void* intraVerifyStringDataItem(const CheckState* state, void* ptr) {
1803 const u1* fileEnd = state->fileEnd;
1804 const u1* data = ptr;
1805 bool okay = true;
1806 u4 utf16Size = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
1807 u4 i;
1808
1809 if (!okay) {
1810 LOGE("Bogus utf16_size\n");
1811 return NULL;
1812 }
1813
1814 for (i = 0; i < utf16Size; i++) {
1815 if (data >= fileEnd) {
1816 LOGE("String data would go beyond end-of-file\n");
1817 return NULL;
1818 }
1819
1820 u1 byte1 = *(data++);
1821
1822 // Switch on the high four bits.
1823 switch (byte1 >> 4) {
1824 case 0x00: {
1825 // Special case of bit pattern 0xxx.
1826 if (byte1 == 0) {
1827 LOGE("String shorter than indicated utf16_size 0x%x\n",
1828 utf16Size);
1829 return NULL;
1830 }
1831 break;
1832 }
1833 case 0x01:
1834 case 0x02:
1835 case 0x03:
1836 case 0x04:
1837 case 0x05:
1838 case 0x06:
1839 case 0x07: {
1840 // Bit pattern 0xxx. No need for any extra bytes or checks.
1841 break;
1842 }
1843 case 0x08:
1844 case 0x09:
1845 case 0x0a:
1846 case 0x0b:
1847 case 0x0f: {
1848 /*
1849 * Bit pattern 10xx or 1111, which are illegal start bytes.
1850 * Note: 1111 is valid for normal UTF-8, but not the
1851 * modified UTF-8 used here.
1852 */
1853 LOGE("Illegal start byte 0x%x\n", byte1);
1854 return NULL;
1855 }
1856 case 0x0e: {
1857 // Bit pattern 1110, so there are two additional bytes.
1858 u1 byte2 = *(data++);
1859 if ((byte2 & 0xc0) != 0x80) {
1860 LOGE("Illegal continuation byte 0x%x\n", byte2);
1861 return NULL;
1862 }
1863 u1 byte3 = *(data++);
1864 if ((byte3 & 0xc0) != 0x80) {
1865 LOGE("Illegal continuation byte 0x%x\n", byte3);
1866 return NULL;
1867 }
1868 u2 value = ((byte1 & 0x0f) << 12) | ((byte2 & 0x3f) << 6)
1869 | (byte3 & 0x3f);
1870 if (value < 0x800) {
1871 LOGE("Illegal representation for value %x\n", value);
1872 return NULL;
1873 }
1874 break;
1875 }
1876 case 0x0c:
1877 case 0x0d: {
1878 // Bit pattern 110x, so there is one additional byte.
1879 u1 byte2 = *(data++);
1880 if ((byte2 & 0xc0) != 0x80) {
1881 LOGE("Illegal continuation byte 0x%x\n", byte2);
1882 return NULL;
1883 }
1884 u2 value = ((byte1 & 0x1f) << 6) | (byte2 & 0x3f);
1885 if ((value != 0) && (value < 0x80)) {
1886 LOGE("Illegal representation for value %x\n", value);
1887 return NULL;
1888 }
1889 break;
1890 }
1891 }
1892 }
1893
1894 if (*(data++) != '\0') {
1895 LOGE("String longer than indicated utf16_size 0x%x\n", utf16Size);
1896 return NULL;
1897 }
1898
1899 return (void*) data;
1900}
1901
1902/* Perform intra-item verification on debug_info_item. */
1903static void* intraVerifyDebugInfoItem(const CheckState* state, void* ptr) {
1904 const u1* fileEnd = state->fileEnd;
1905 const u1* data = ptr;
1906 bool okay = true;
1907 u4 i;
1908
1909 readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
1910
1911 if (!okay) {
1912 LOGE("Bogus line_start\n");
1913 return NULL;
1914 }
1915
1916 u4 parametersSize =
1917 readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
1918
1919 if (!okay) {
1920 LOGE("Bogus parameters_size\n");
1921 return NULL;
1922 }
1923
1924 if (parametersSize > 65536) {
1925 LOGE("Invalid parameters_size: 0x%x\n", parametersSize);
1926 return NULL;
1927 }
1928
1929 for (i = 0; i < parametersSize; i++) {
1930 u4 parameterName =
1931 readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
1932
1933 if (!okay) {
1934 LOGE("Bogus parameter_name\n");
1935 return NULL;
1936 }
1937
1938 if (parameterName != 0) {
1939 parameterName--;
1940 CHECK_INDEX(parameterName, state->pHeader->stringIdsSize);
1941 }
1942 }
1943
1944 bool done = false;
1945 while (!done) {
1946 u1 opcode = *(data++);
1947
1948 switch (opcode) {
1949 case DBG_END_SEQUENCE: {
1950 done = true;
1951 break;
1952 }
1953 case DBG_ADVANCE_PC: {
1954 readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
1955 break;
1956 }
1957 case DBG_ADVANCE_LINE: {
1958 readAndVerifySignedLeb128(&data, fileEnd, &okay);
1959 break;
1960 }
1961 case DBG_START_LOCAL: {
1962 u4 idx;
1963 u4 regNum = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
1964 if (!okay) break;
1965 if (regNum >= 65536) {
1966 okay = false;
1967 break;
1968 }
1969 idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
1970 if (!okay) break;
1971 if (idx != 0) {
1972 idx--;
1973 CHECK_INDEX(idx, state->pHeader->stringIdsSize);
1974 }
1975 idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
1976 if (!okay) break;
1977 if (idx != 0) {
1978 idx--;
1979 CHECK_INDEX(idx, state->pHeader->stringIdsSize);
1980 }
1981 break;
1982 }
1983 case DBG_END_LOCAL:
1984 case DBG_RESTART_LOCAL: {
1985 u4 regNum = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
1986 if (!okay) break;
1987 if (regNum >= 65536) {
1988 okay = false;
1989 break;
1990 }
1991 break;
1992 }
1993 case DBG_START_LOCAL_EXTENDED: {
1994 u4 idx;
1995 u4 regNum = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
1996 if (!okay) break;
1997 if (regNum >= 65536) {
1998 okay = false;
1999 break;
2000 }
2001 idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2002 if (!okay) break;
2003 if (idx != 0) {
2004 idx--;
2005 CHECK_INDEX(idx, state->pHeader->stringIdsSize);
2006 }
2007 idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2008 if (!okay) break;
2009 if (idx != 0) {
2010 idx--;
2011 CHECK_INDEX(idx, state->pHeader->stringIdsSize);
2012 }
2013 idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2014 if (!okay) break;
2015 if (idx != 0) {
2016 idx--;
2017 CHECK_INDEX(idx, state->pHeader->stringIdsSize);
2018 }
2019 break;
2020 }
2021 case DBG_SET_FILE: {
2022 u4 idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2023 if (!okay) break;
2024 if (idx != 0) {
2025 idx--;
2026 CHECK_INDEX(idx, state->pHeader->stringIdsSize);
2027 }
2028 break;
2029 }
2030 default: {
2031 // No arguments to parse for anything else.
2032 }
2033 }
2034
2035 if (!okay) {
2036 LOGE("Bogus syntax for opcode %02x\n", opcode);
2037 return NULL;
2038 }
2039 }
2040
2041 return (void*) data;
2042}
2043
2044/* defined below */
2045static const u1* verifyEncodedValue(const CheckState* state, const u1* data,
2046 bool crossVerify);
2047static const u1* verifyEncodedAnnotation(const CheckState* state,
2048 const u1* data, bool crossVerify);
2049
2050/* Helper for verifyEncodedValue(), which reads a 1- to 4- byte unsigned
2051 * little endian value. */
2052static u4 readUnsignedLittleEndian(const CheckState* state, const u1** pData,
2053 u4 size) {
2054 const u1* data = *pData;
2055 u4 result = 0;
2056 u4 i;
2057
2058 CHECK_PTR_RANGE(data, data + size);
2059
2060 for (i = 0; i < size; i++) {
2061 result |= ((u4) *(data++)) << (i * 8);
2062 }
2063
2064 *pData = data;
2065 return result;
2066}
2067
2068/* Helper for *VerifyAnnotationItem() and *VerifyEncodedArrayItem(), which
2069 * verifies an encoded_array. */
2070static const u1* verifyEncodedArray(const CheckState* state,
2071 const u1* data, bool crossVerify) {
2072 bool okay = true;
2073 u4 size = readAndVerifyUnsignedLeb128(&data, state->fileEnd, &okay);
2074
2075 if (!okay) {
2076 LOGE("Bogus encoded_array size\n");
2077 return NULL;
2078 }
2079
2080 while (size--) {
2081 data = verifyEncodedValue(state, data, crossVerify);
2082 if (data == NULL) {
Andy McFaddenab0f0a02009-03-27 12:19:29 -07002083 LOGE("Bogus encoded_array value\n");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002084 return NULL;
2085 }
2086 }
2087
2088 return data;
2089}
2090
2091/* Helper for *VerifyAnnotationItem() and *VerifyEncodedArrayItem(), which
2092 * verifies an encoded_value. */
2093static const u1* verifyEncodedValue(const CheckState* state,
2094 const u1* data, bool crossVerify) {
2095 CHECK_PTR_RANGE(data, data + 1);
2096
2097 u1 headerByte = *(data++);
2098 u4 valueType = headerByte & kDexAnnotationValueTypeMask;
2099 u4 valueArg = headerByte >> kDexAnnotationValueArgShift;
2100
2101 switch (valueType) {
2102 case kDexAnnotationByte: {
2103 if (valueArg != 0) {
2104 LOGE("Bogus byte size 0x%x\n", valueArg);
2105 return NULL;
2106 }
2107 data++;
2108 break;
2109 }
2110 case kDexAnnotationShort:
2111 case kDexAnnotationChar: {
2112 if (valueArg > 1) {
2113 LOGE("Bogus char/short size 0x%x\n", valueArg);
2114 return NULL;
2115 }
2116 data += valueArg + 1;
2117 break;
2118 }
2119 case kDexAnnotationInt:
2120 case kDexAnnotationFloat: {
2121 if (valueArg > 3) {
2122 LOGE("Bogus int/float size 0x%x\n", valueArg);
2123 return NULL;
2124 }
2125 data += valueArg + 1;
2126 break;
2127 }
2128 case kDexAnnotationLong:
2129 case kDexAnnotationDouble: {
2130 data += valueArg + 1;
2131 break;
2132 }
2133 case kDexAnnotationString: {
2134 if (valueArg > 3) {
2135 LOGE("Bogus string size 0x%x\n", valueArg);
2136 return NULL;
2137 }
2138 u4 idx = readUnsignedLittleEndian(state, &data, valueArg + 1);
2139 CHECK_INDEX(idx, state->pHeader->stringIdsSize);
2140 break;
2141 }
2142 case kDexAnnotationType: {
2143 if (valueArg > 3) {
2144 LOGE("Bogus type size 0x%x\n", valueArg);
2145 return NULL;
2146 }
2147 u4 idx = readUnsignedLittleEndian(state, &data, valueArg + 1);
2148 CHECK_INDEX(idx, state->pHeader->typeIdsSize);
2149 break;
2150 }
2151 case kDexAnnotationField:
2152 case kDexAnnotationEnum: {
2153 if (valueArg > 3) {
2154 LOGE("Bogus field/enum size 0x%x\n", valueArg);
2155 return NULL;
2156 }
2157 u4 idx = readUnsignedLittleEndian(state, &data, valueArg + 1);
2158 CHECK_INDEX(idx, state->pHeader->fieldIdsSize);
2159 break;
2160 }
2161 case kDexAnnotationMethod: {
2162 if (valueArg > 3) {
2163 LOGE("Bogus method size 0x%x\n", valueArg);
2164 return NULL;
2165 }
2166 u4 idx = readUnsignedLittleEndian(state, &data, valueArg + 1);
2167 CHECK_INDEX(idx, state->pHeader->methodIdsSize);
2168 break;
2169 }
2170 case kDexAnnotationArray: {
2171 if (valueArg != 0) {
2172 LOGE("Bogus array value_arg 0x%x\n", valueArg);
2173 return NULL;
2174 }
2175 data = verifyEncodedArray(state, data, crossVerify);
2176 break;
2177 }
2178 case kDexAnnotationAnnotation: {
2179 if (valueArg != 0) {
2180 LOGE("Bogus annotation value_arg 0x%x\n", valueArg);
2181 return NULL;
2182 }
2183 data = verifyEncodedAnnotation(state, data, crossVerify);
2184 break;
2185 }
2186 case kDexAnnotationNull: {
2187 if (valueArg != 0) {
2188 LOGE("Bogus null value_arg 0x%x\n", valueArg);
2189 return NULL;
2190 }
2191 // Nothing else to do for this type.
2192 break;
2193 }
2194 case kDexAnnotationBoolean: {
2195 if (valueArg > 1) {
2196 LOGE("Bogus boolean value_arg 0x%x\n", valueArg);
2197 return NULL;
2198 }
2199 // Nothing else to do for this type.
2200 break;
2201 }
2202 default: {
2203 LOGE("Bogus value_type 0x%x\n", valueType);
2204 return NULL;
2205 }
2206 }
2207
2208 return data;
2209}
2210
2211/* Helper for *VerifyAnnotationItem() and *VerifyEncodedArrayItem(), which
2212 * verifies an encoded_annotation. */
2213static const u1* verifyEncodedAnnotation(const CheckState* state,
2214 const u1* data, bool crossVerify) {
2215 const u1* fileEnd = state->fileEnd;
2216 bool okay = true;
2217 u4 idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2218
2219 if (!okay) {
2220 LOGE("Bogus encoded_annotation type_idx\n");
2221 return NULL;
2222 }
2223
2224 CHECK_INDEX(idx, state->pHeader->typeIdsSize);
2225
2226 if (crossVerify) {
2227 const char* descriptor = dexStringByTypeIdx(state->pDexFile, idx);
2228 if (!dexIsClassDescriptor(descriptor)) {
2229 LOGE("Bogus annotation type: '%s'\n", descriptor);
2230 return NULL;
2231 }
2232 }
2233
2234 u4 size = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2235 u4 lastIdx = 0;
2236 bool first = true;
2237
2238 if (!okay) {
2239 LOGE("Bogus encoded_annotation size\n");
2240 return NULL;
2241 }
2242
2243 while (size--) {
2244 idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2245
2246 if (!okay) {
2247 LOGE("Bogus encoded_annotation name_idx\n");
2248 return NULL;
2249 }
2250
2251 CHECK_INDEX(idx, state->pHeader->stringIdsSize);
2252
2253 if (crossVerify) {
2254 const char* name = dexStringById(state->pDexFile, idx);
2255 if (!dexIsValidMemberName(name)) {
2256 LOGE("Bogus annotation member name: '%s'\n", name);
2257 return NULL;
2258 }
2259 }
2260
2261 if (first) {
2262 first = false;
2263 } else if (lastIdx >= idx) {
2264 LOGE("Out-of-order encoded_annotation name_idx: 0x%x then 0x%x\n",
2265 lastIdx, idx);
2266 return NULL;
2267 }
2268
2269 data = verifyEncodedValue(state, data, crossVerify);
2270 lastIdx = idx;
2271
2272 if (data == NULL) {
2273 return NULL;
2274 }
2275 }
2276
2277 return data;
2278}
2279
2280/* Perform intra-item verification on encoded_array_item. */
2281static void* intraVerifyEncodedArrayItem(const CheckState* state, void* ptr) {
2282 return (void*) verifyEncodedArray(state, (const u1*) ptr, false);
2283}
2284
2285/* Perform intra-item verification on annotation_item. */
2286static void* intraVerifyAnnotationItem(const CheckState* state, void* ptr) {
2287 const u1* data = ptr;
2288
2289 CHECK_PTR_RANGE(data, data + 1);
2290
2291 switch (*(data++)) {
2292 case kDexVisibilityBuild:
2293 case kDexVisibilityRuntime:
2294 case kDexVisibilitySystem: {
2295 break;
2296 }
2297 default: {
2298 LOGE("Bogus annotation visibility: 0x%x\n", *data);
2299 return NULL;
2300 }
2301 }
2302
2303 return (void*) verifyEncodedAnnotation(state, data, false);
2304}
2305
2306/* Perform cross-item verification on annotation_item. */
2307static void* crossVerifyAnnotationItem(const CheckState* state, void* ptr) {
2308 const u1* data = ptr;
2309
2310 // Skip the visibility byte.
2311 data++;
2312
2313 return (void*) verifyEncodedAnnotation(state, data, true);
2314}
2315
2316
2317
2318
2319/*
2320 * Function to visit an individual top-level item type.
2321 */
2322typedef void* ItemVisitorFunction(const CheckState* state, void* ptr);
2323
2324/*
2325 * Iterate over all the items in a section, optionally updating the
2326 * data map (done if mapType is passed as non-negative). The section
2327 * must consist of concatenated items of the same type.
2328 */
2329static bool iterateSectionWithOptionalUpdate(CheckState* state,
2330 u4 offset, u4 count, ItemVisitorFunction* func, u4 alignment,
2331 u4* nextOffset, int mapType) {
2332 u4 alignmentMask = alignment - 1;
2333 u4 i;
2334
2335 state->previousItem = NULL;
2336
2337 for (i = 0; i < count; i++) {
2338 u4 newOffset = (offset + alignmentMask) & ~alignmentMask;
2339 u1* ptr = filePointer(state, newOffset);
2340
2341 if (offset < newOffset) {
2342 ptr = filePointer(state, offset);
2343 if (offset < newOffset) {
2344 CHECK_OFFSET_RANGE(offset, newOffset);
2345 while (offset < newOffset) {
2346 if (*ptr != '\0') {
2347 LOGE("Non-zero padding 0x%02x @ %x\n", *ptr, offset);
2348 return false;
2349 }
2350 ptr++;
2351 offset++;
2352 }
2353 }
2354 }
2355
2356 u1* newPtr = (u1*) func(state, ptr);
2357 newOffset = fileOffset(state, newPtr);
2358
2359 if (newPtr == NULL) {
2360 LOGE("Trouble with item %d @ offset 0x%x\n", i, offset);
2361 return false;
2362 }
2363
2364 if (newOffset > state->fileLen) {
2365 LOGE("Item %d @ offset 0x%x ends out of bounds\n", i, offset);
2366 return false;
2367 }
2368
2369 if (mapType >= 0) {
2370 dexDataMapAdd(state->pDataMap, offset, mapType);
2371 }
2372
2373 state->previousItem = ptr;
2374 offset = newOffset;
2375 }
2376
2377 if (nextOffset != NULL) {
2378 *nextOffset = offset;
2379 }
2380
2381 return true;
2382}
2383
2384/*
2385 * Iterate over all the items in a section. The section must consist of
2386 * concatenated items of the same type. This variant will not update the data
2387 * map.
2388 */
2389static bool iterateSection(CheckState* state, u4 offset, u4 count,
2390 ItemVisitorFunction* func, u4 alignment, u4* nextOffset) {
2391 return iterateSectionWithOptionalUpdate(state, offset, count, func,
2392 alignment, nextOffset, -1);
2393}
2394
2395/*
2396 * Like iterateSection(), but also check that the offset and count match
2397 * a given pair of expected values.
2398 */
2399static bool checkBoundsAndIterateSection(CheckState* state,
2400 u4 offset, u4 count, u4 expectedOffset, u4 expectedCount,
2401 ItemVisitorFunction* func, u4 alignment, u4* nextOffset) {
2402 if (offset != expectedOffset) {
2403 LOGE("Bogus offset for section: got 0x%x; expected 0x%x\n",
2404 offset, expectedOffset);
2405 return false;
2406 }
2407
2408 if (count != expectedCount) {
2409 LOGE("Bogus size for section: got 0x%x; expected 0x%x\n",
2410 count, expectedCount);
2411 return false;
2412 }
2413
2414 return iterateSection(state, offset, count, func, alignment, nextOffset);
2415}
2416
2417/*
2418 * Like iterateSection(), but also update the data section map and
2419 * check that all the items fall within the data section.
2420 */
2421static bool iterateDataSection(CheckState* state, u4 offset, u4 count,
2422 ItemVisitorFunction* func, u4 alignment, u4* nextOffset, int mapType) {
2423 u4 dataStart = state->pHeader->dataOff;
2424 u4 dataEnd = dataStart + state->pHeader->dataSize;
2425
2426 assert(nextOffset != NULL);
2427
2428 if ((offset < dataStart) || (offset >= dataEnd)) {
2429 LOGE("Bogus offset for data subsection: 0x%x\n", offset);
2430 return false;
2431 }
2432
2433 if (!iterateSectionWithOptionalUpdate(state, offset, count, func,
2434 alignment, nextOffset, mapType)) {
2435 return false;
2436 }
2437
2438 if (*nextOffset > dataEnd) {
2439 LOGE("Out-of-bounds end of data subsection: 0x%x\n", *nextOffset);
2440 return false;
2441 }
2442
2443 return true;
2444}
2445
2446/*
2447 * Byte-swap all items in the given map except the header and the map
2448 * itself, both of which should have already gotten swapped. This also
2449 * does all possible intra-item verification, that is, verification
2450 * that doesn't need to assume the sanctity of the contents of *other*
2451 * items. The intra-item limitation is because at the time an item is
2452 * asked to verify itself, it can't assume that the items it refers to
2453 * have been byte-swapped and verified.
2454 */
2455static bool swapEverythingButHeaderAndMap(CheckState* state,
2456 DexMapList* pMap) {
2457 const DexMapItem* item = pMap->list;
2458 u4 lastOffset = 0;
2459 u4 count = pMap->size;
2460 bool okay = true;
2461
2462 while (okay && count--) {
2463 u4 sectionOffset = item->offset;
2464 u4 sectionCount = item->size;
2465 u2 type = item->type;
2466
2467 if (lastOffset < sectionOffset) {
2468 CHECK_OFFSET_RANGE(lastOffset, sectionOffset);
2469 const u1* ptr = filePointer(state, lastOffset);
2470 while (lastOffset < sectionOffset) {
2471 if (*ptr != '\0') {
2472 LOGE("Non-zero padding 0x%02x before section start @ %x\n",
2473 *ptr, lastOffset);
2474 okay = false;
2475 break;
2476 }
2477 ptr++;
2478 lastOffset++;
2479 }
2480 } else if (lastOffset > sectionOffset) {
2481 LOGE("Section overlap or out-of-order map: %x, %x\n",
2482 lastOffset, sectionOffset);
2483 okay = false;
2484 }
2485
2486 if (!okay) {
2487 break;
2488 }
2489
2490 switch (type) {
2491 case kDexTypeHeaderItem: {
2492 /*
2493 * The header got swapped very early on, but do some
2494 * additional sanity checking here.
2495 */
2496 okay = checkHeaderSection(state, sectionOffset, sectionCount,
2497 &lastOffset);
2498 break;
2499 }
2500 case kDexTypeStringIdItem: {
2501 okay = checkBoundsAndIterateSection(state, sectionOffset,
2502 sectionCount, state->pHeader->stringIdsOff,
2503 state->pHeader->stringIdsSize, swapStringIdItem,
2504 sizeof(u4), &lastOffset);
2505 break;
2506 }
2507 case kDexTypeTypeIdItem: {
2508 okay = checkBoundsAndIterateSection(state, sectionOffset,
2509 sectionCount, state->pHeader->typeIdsOff,
2510 state->pHeader->typeIdsSize, swapTypeIdItem,
2511 sizeof(u4), &lastOffset);
2512 break;
2513 }
2514 case kDexTypeProtoIdItem: {
2515 okay = checkBoundsAndIterateSection(state, sectionOffset,
2516 sectionCount, state->pHeader->protoIdsOff,
2517 state->pHeader->protoIdsSize, swapProtoIdItem,
2518 sizeof(u4), &lastOffset);
2519 break;
2520 }
2521 case kDexTypeFieldIdItem: {
2522 okay = checkBoundsAndIterateSection(state, sectionOffset,
2523 sectionCount, state->pHeader->fieldIdsOff,
2524 state->pHeader->fieldIdsSize, swapFieldIdItem,
2525 sizeof(u4), &lastOffset);
2526 break;
2527 }
2528 case kDexTypeMethodIdItem: {
2529 okay = checkBoundsAndIterateSection(state, sectionOffset,
2530 sectionCount, state->pHeader->methodIdsOff,
2531 state->pHeader->methodIdsSize, swapMethodIdItem,
2532 sizeof(u4), &lastOffset);
2533 break;
2534 }
2535 case kDexTypeClassDefItem: {
2536 okay = checkBoundsAndIterateSection(state, sectionOffset,
2537 sectionCount, state->pHeader->classDefsOff,
2538 state->pHeader->classDefsSize, swapClassDefItem,
2539 sizeof(u4), &lastOffset);
2540 break;
2541 }
2542 case kDexTypeMapList: {
2543 /*
2544 * The map section was swapped early on, but do some
2545 * additional sanity checking here.
2546 */
2547 okay = checkMapSection(state, sectionOffset, sectionCount,
2548 &lastOffset);
2549 break;
2550 }
2551 case kDexTypeTypeList: {
2552 okay = iterateDataSection(state, sectionOffset, sectionCount,
2553 swapTypeList, sizeof(u4), &lastOffset, type);
2554 break;
2555 }
2556 case kDexTypeAnnotationSetRefList: {
2557 okay = iterateDataSection(state, sectionOffset, sectionCount,
2558 swapAnnotationSetRefList, sizeof(u4), &lastOffset,
2559 type);
2560 break;
2561 }
2562 case kDexTypeAnnotationSetItem: {
2563 okay = iterateDataSection(state, sectionOffset, sectionCount,
2564 swapAnnotationSetItem, sizeof(u4), &lastOffset, type);
2565 break;
2566 }
2567 case kDexTypeClassDataItem: {
2568 okay = iterateDataSection(state, sectionOffset, sectionCount,
2569 intraVerifyClassDataItem, sizeof(u1), &lastOffset,
2570 type);
2571 break;
2572 }
2573 case kDexTypeCodeItem: {
2574 okay = iterateDataSection(state, sectionOffset, sectionCount,
2575 swapCodeItem, sizeof(u4), &lastOffset, type);
2576 break;
2577 }
2578 case kDexTypeStringDataItem: {
2579 okay = iterateDataSection(state, sectionOffset, sectionCount,
2580 intraVerifyStringDataItem, sizeof(u1), &lastOffset,
2581 type);
2582 break;
2583 }
2584 case kDexTypeDebugInfoItem: {
2585 okay = iterateDataSection(state, sectionOffset, sectionCount,
2586 intraVerifyDebugInfoItem, sizeof(u1), &lastOffset,
2587 type);
2588 break;
2589 }
2590 case kDexTypeAnnotationItem: {
2591 okay = iterateDataSection(state, sectionOffset, sectionCount,
2592 intraVerifyAnnotationItem, sizeof(u1), &lastOffset,
2593 type);
2594 break;
2595 }
2596 case kDexTypeEncodedArrayItem: {
2597 okay = iterateDataSection(state, sectionOffset, sectionCount,
2598 intraVerifyEncodedArrayItem, sizeof(u1), &lastOffset,
2599 type);
2600 break;
2601 }
2602 case kDexTypeAnnotationsDirectoryItem: {
2603 okay = iterateDataSection(state, sectionOffset, sectionCount,
2604 swapAnnotationsDirectoryItem, sizeof(u4), &lastOffset,
2605 type);
2606 break;
2607 }
2608 default: {
2609 LOGE("Unknown map item type %04x\n", type);
2610 return false;
2611 }
2612 }
2613
2614 if (!okay) {
2615 LOGE("Swap of section type %04x failed\n", type);
2616 }
2617
2618 item++;
2619 }
2620
2621 return okay;
2622}
2623
2624/*
2625 * Perform cross-item verification on everything that needs it. This
2626 * pass is only called after all items are byte-swapped and
2627 * intra-verified (checked for internal consistency).
2628 */
2629static bool crossVerifyEverything(CheckState* state, DexMapList* pMap)
2630{
2631 const DexMapItem* item = pMap->list;
2632 u4 count = pMap->size;
2633 bool okay = true;
2634
2635 while (okay && count--) {
2636 u4 sectionOffset = item->offset;
2637 u4 sectionCount = item->size;
2638
2639 switch (item->type) {
2640 case kDexTypeHeaderItem:
2641 case kDexTypeMapList:
2642 case kDexTypeTypeList:
2643 case kDexTypeCodeItem:
2644 case kDexTypeStringDataItem:
2645 case kDexTypeDebugInfoItem:
2646 case kDexTypeAnnotationItem:
2647 case kDexTypeEncodedArrayItem: {
2648 // There is no need for cross-item verification for these.
2649 break;
2650 }
2651 case kDexTypeStringIdItem: {
2652 okay = iterateSection(state, sectionOffset, sectionCount,
2653 crossVerifyStringIdItem, sizeof(u4), NULL);
2654 break;
2655 }
2656 case kDexTypeTypeIdItem: {
2657 okay = iterateSection(state, sectionOffset, sectionCount,
2658 crossVerifyTypeIdItem, sizeof(u4), NULL);
2659 break;
2660 }
2661 case kDexTypeProtoIdItem: {
2662 okay = iterateSection(state, sectionOffset, sectionCount,
2663 crossVerifyProtoIdItem, sizeof(u4), NULL);
2664 break;
2665 }
2666 case kDexTypeFieldIdItem: {
2667 okay = iterateSection(state, sectionOffset, sectionCount,
2668 crossVerifyFieldIdItem, sizeof(u4), NULL);
2669 break;
2670 }
2671 case kDexTypeMethodIdItem: {
2672 okay = iterateSection(state, sectionOffset, sectionCount,
2673 crossVerifyMethodIdItem, sizeof(u4), NULL);
2674 break;
2675 }
2676 case kDexTypeClassDefItem: {
2677 okay = iterateSection(state, sectionOffset, sectionCount,
2678 crossVerifyClassDefItem, sizeof(u4), NULL);
2679 break;
2680 }
2681 case kDexTypeAnnotationSetRefList: {
2682 okay = iterateSection(state, sectionOffset, sectionCount,
2683 crossVerifyAnnotationSetRefList, sizeof(u4), NULL);
2684 break;
2685 }
2686 case kDexTypeAnnotationSetItem: {
2687 okay = iterateSection(state, sectionOffset, sectionCount,
2688 crossVerifyAnnotationSetItem, sizeof(u4), NULL);
2689 break;
2690 }
2691 case kDexTypeClassDataItem: {
2692 okay = iterateSection(state, sectionOffset, sectionCount,
2693 crossVerifyClassDataItem, sizeof(u1), NULL);
2694 break;
2695 }
2696 case kDexTypeAnnotationsDirectoryItem: {
2697 okay = iterateSection(state, sectionOffset, sectionCount,
2698 crossVerifyAnnotationsDirectoryItem, sizeof(u4), NULL);
2699 break;
2700 }
2701 default: {
2702 LOGE("Unknown map item type %04x\n", item->type);
2703 return false;
2704 }
2705 }
2706
2707 if (!okay) {
2708 LOGE("Cross-item verify of section type %04x failed\n",
2709 item->type);
2710 }
2711
2712 item++;
2713 }
2714
2715 return okay;
2716}
2717
2718/*
2719 * Fix the byte ordering of all fields in the DEX file, and do structural
2720 * verification.
2721 *
2722 * While we're at it, make sure that the file offsets all refer to locations
2723 * within the file.
2724 *
2725 * Returns 0 on success, nonzero on failure.
2726 */
2727int dexFixByteOrdering(u1* addr, int len)
2728{
2729 DexHeader* pHeader;
2730 CheckState state;
2731 bool okay = true;
2732
2733 memset(&state, 0, sizeof(state));
2734 LOGV("+++ swapping and verifying\n");
2735
2736 /*
2737 * Start by verifying the magic number. The caller verified that "len"
2738 * says we have at least a header's worth of data.
2739 */
2740 pHeader = (DexHeader*) addr;
2741 if (memcmp(pHeader->magic, DEX_MAGIC, 4) != 0) {
2742 /* really shouldn't be here -- this is weird */
2743 LOGE("ERROR: Can't byte swap: bad magic number "
2744 "(0x%02x %02x %02x %02x)\n",
2745 pHeader->magic[0], pHeader->magic[1],
2746 pHeader->magic[2], pHeader->magic[3]);
2747 okay = false;
2748 }
2749
2750 if (okay && memcmp(pHeader->magic+4, DEX_MAGIC_VERS, 4) != 0) {
2751 /* older or newer version we don't know how to read */
2752 LOGE("ERROR: Can't byte swap: bad dex version "
2753 "(0x%02x %02x %02x %02x)\n",
2754 pHeader->magic[4], pHeader->magic[5],
2755 pHeader->magic[6], pHeader->magic[7]);
2756 okay = false;
2757 }
2758
2759 if (okay) {
2760 int expectedLen = (int) SWAP4(pHeader->fileSize);
2761 if (len < expectedLen) {
2762 LOGE("ERROR: Bad length: expected %d, got %d\n", expectedLen, len);
2763 okay = false;
2764 } else if (len != expectedLen) {
2765 LOGW("WARNING: Odd length: expected %d, got %d\n", expectedLen,
2766 len);
2767 // keep going
2768 }
2769 }
2770
2771 if (okay) {
2772 /*
2773 * Compute the adler32 checksum and compare it to what's stored in
2774 * the file. This isn't free, but chances are good that we just
2775 * unpacked this from a jar file and have all of the pages sitting
2776 * in memory, so it's pretty quick.
2777 *
2778 * This might be a big-endian system, so we need to do this before
2779 * we byte-swap the header.
2780 */
2781 uLong adler = adler32(0L, Z_NULL, 0);
2782 const int nonSum = sizeof(pHeader->magic) + sizeof(pHeader->checksum);
2783 u4 storedFileSize = SWAP4(pHeader->fileSize);
2784 u4 expectedChecksum = SWAP4(pHeader->checksum);
2785
2786 adler = adler32(adler, ((const u1*) pHeader) + nonSum,
2787 storedFileSize - nonSum);
2788
2789 if (adler != expectedChecksum) {
2790 LOGE("ERROR: bad checksum (%08lx, expected %08x)\n",
2791 adler, expectedChecksum);
2792 okay = false;
2793 }
2794 }
2795
2796 if (okay) {
2797 state.fileStart = addr;
2798 state.fileEnd = addr + len;
2799 state.fileLen = len;
2800 state.pDexFile = NULL;
2801 state.pDataMap = NULL;
2802 state.previousItem = NULL;
2803
2804 /*
2805 * Swap the header and check the contents.
2806 */
2807 okay = swapDexHeader(&state, pHeader);
2808 }
2809
2810 if (okay) {
2811 state.pHeader = pHeader;
2812
2813 if (pHeader->headerSize < sizeof(DexHeader)) {
2814 LOGE("ERROR: Small header size %d, struct %d\n",
2815 pHeader->headerSize, (int) sizeof(DexHeader));
2816 okay = false;
2817 } else if (pHeader->headerSize > sizeof(DexHeader)) {
2818 LOGW("WARNING: Large header size %d, struct %d\n",
2819 pHeader->headerSize, (int) sizeof(DexHeader));
2820 // keep going?
2821 }
2822 }
2823
2824 if (okay) {
2825 /*
2826 * Look for the map. Swap it and then use it to find and swap
2827 * everything else.
2828 */
2829 if (pHeader->mapOff != 0) {
2830 DexFile dexFile;
2831 DexMapList* pDexMap = (DexMapList*) (addr + pHeader->mapOff);
2832
2833 okay = okay && swapMap(&state, pDexMap);
2834 okay = okay && swapEverythingButHeaderAndMap(&state, pDexMap);
2835
2836 dexFileSetupBasicPointers(&dexFile, addr);
2837 state.pDexFile = &dexFile;
2838
2839 okay = okay && crossVerifyEverything(&state, pDexMap);
2840 } else {
2841 LOGE("ERROR: No map found; impossible to byte-swap and verify");
2842 okay = false;
2843 }
2844 }
2845
2846 if (!okay) {
2847 LOGE("ERROR: Byte swap + verify failed\n");
2848 }
2849
2850 if (state.pDataMap != NULL) {
2851 dexDataMapFree(state.pDataMap);
2852 }
2853
2854 return !okay; // 0 == success
2855}