2 * Copyright (C) 2008 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 * Byte-swapping and verification of dex files.
23 #include "DexDataMap.h"
34 # error "byte ordering not defined"
37 #if __BYTE_ORDER == __LITTLE_ENDIAN
38 # define SWAP2(_value) (_value)
39 # define SWAP4(_value) (_value)
40 # define SWAP8(_value) (_value)
42 # define SWAP2(_value) endianSwapU2((_value))
43 # define SWAP4(_value) endianSwapU4((_value))
44 # define SWAP8(_value) endianSwapU8((_value))
45 static u2 endianSwapU2(u2 value) {
46 return (value >> 8) | (value << 8);
48 static u4 endianSwapU4(u4 value) {
49 /* ABCD --> CDAB --> DCBA */
50 value = (value >> 16) | (value << 16);
51 return ((value & 0xff00ff00) >> 8) | ((value << 8) & 0xff00ff00);
53 static 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);
63 #define SWAP_FIELD2(_field) (_field) = SWAP2(_field)
64 #define SWAP_FIELD4(_field) (_field) = SWAP4(_field)
65 #define SWAP_FIELD8(_field) (_field) = SWAP8(_field)
68 * Some information we pass around to help verify values.
70 typedef struct CheckState {
71 const DexHeader* pHeader;
73 const u1* fileEnd; // points to fileStart + fileLen
75 DexDataMap* pDataMap; // set after map verification
76 const DexFile* pDexFile; // set after intraitem verification
79 * bitmap of type_id indices that have been used to define classes;
80 * initialized immediately before class_def cross-verification, and
81 * freed immediately after it
83 u4* pDefinedClassBits;
85 const void* previousItem; // set during section iteration
89 * Return the file offset of the given pointer.
91 static inline u4 fileOffset(const CheckState* state, const void* ptr) {
92 return ((const u1*) ptr) - state->fileStart;
96 * Return a pointer for the given file offset.
98 static inline void* filePointer(const CheckState* state, u4 offset) {
99 return (void*) (state->fileStart + offset);
103 * Verify that a pointer range, start inclusive to end exclusive, only
104 * covers bytes in the file and doesn't point beyond the end of the
105 * file. That is, the start must indicate a valid byte or may point at
106 * the byte just past the end of the file (but no further), and the
107 * end must be no less than the start and must also not point beyond
108 * the byte just past the end of the file.
110 static inline bool checkPtrRange(const CheckState* state,
111 const void* start, const void* end, const char* label) {
112 const void* fileStart = state->fileStart;
113 const void* fileEnd = state->fileEnd;
114 if ((start < fileStart) || (start > fileEnd)
115 || (end < start) || (end > fileEnd)) {
116 LOGW("Bad offset range for %s: 0x%x..0x%x\n", label,
117 fileOffset(state, start), fileOffset(state, end));
124 * Verify that a range of offsets, start inclusive to end exclusive,
125 * are all valid. That is, the start must indicate a valid byte or may
126 * point at the byte just past the end of the file (but no further),
127 * and the end must be no less than the start and must also not point
128 * beyond the byte just past the end of the file.
130 * Assumes "const CheckState* state".
132 #define CHECK_OFFSET_RANGE(_start, _end) { \
133 const u1* _startPtr = filePointer(state, (_start)); \
134 const u1* _endPtr = filePointer(state, (_end)); \
135 if (!checkPtrRange(state, _startPtr, _endPtr, \
136 #_start ".." #_end)) { \
142 * Verify that a pointer range, start inclusive to end exclusive, only
143 * covers bytes in the file and doesn't point beyond the end of the
144 * file. That is, the start must indicate a valid byte or may point at
145 * the byte just past the end of the file (but no further), and the
146 * end must be no less than the start and must also not point beyond
147 * the byte just past the end of the file.
149 * Assumes "const CheckState* state".
151 #define CHECK_PTR_RANGE(_start, _end) { \
152 if (!checkPtrRange(state, (_start), (_end), #_start ".." #_end)) { \
158 * Make sure a list of items fits entirely within the file.
160 * Assumes "const CheckState* state" and "typeof(_count) == typeof(_elemSize)"
161 * If the type sizes or signs are mismatched, this will return 0.
163 #define CHECK_LIST_SIZE(_ptr, _count, _elemSize) { \
164 const u1* _start = (const u1*) (_ptr); \
165 const u1* _end = _start + ((_count) * (_elemSize)); \
166 if (!safe_mul(NULL, (_count), (_elemSize)) || \
167 !checkPtrRange(state, _start, _end, #_ptr)) { \
173 * Swap a field that is known to hold an absolute DEX file offset. Note:
174 * This does not check to see that the swapped offset points within the
175 * mapped file, since that should be handled (with even more rigor) by
176 * the cross-verification phase.
178 * Assumes "const CheckState* state".
180 #define SWAP_OFFSET4(_field) { \
181 SWAP_FIELD4((_field)); \
185 * Verify that an index falls in a valid range.
187 #define CHECK_INDEX(_field, _limit) { \
188 if ((_field) >= (_limit)) { \
189 LOGW("Bad index: %s(%u) > %s(%u)\n", \
190 #_field, (u4)(_field), #_limit, (u4)(_limit)); \
196 * Swap an index, and verify that it falls in a valid range.
198 #define SWAP_INDEX2(_field, _limit) { \
199 SWAP_FIELD2((_field)); \
200 CHECK_INDEX((_field), (_limit)); \
204 * Verify that an index falls in a valid range or is kDexNoIndex.
206 #define CHECK_INDEX_OR_NOINDEX(_field, _limit) { \
207 if ((_field) != kDexNoIndex && (_field) >= (_limit)) { \
208 LOGW("Bad index: %s(%u) > %s(%u)\n", \
209 #_field, (u4)(_field), #_limit, (u4)(_limit)); \
215 * Swap an index, and verify that it falls in a valid range.
217 #define SWAP_INDEX4(_field, _limit) { \
218 SWAP_FIELD4((_field)); \
219 CHECK_INDEX((_field), (_limit)); \
223 * Swap an index, and verify that it falls in a valid range or is
226 #define SWAP_INDEX4_OR_NOINDEX(_field, _limit) { \
227 SWAP_FIELD4((_field)); \
228 CHECK_INDEX_OR_NOINDEX((_field), (_limit)); \
231 /* Verify the definer of a given field_idx. */
232 static bool verifyFieldDefiner(const CheckState* state, u4 definingClass,
234 const DexFieldId* field = dexGetFieldId(state->pDexFile, fieldIdx);
235 return field->classIdx == definingClass;
238 /* Verify the definer of a given method_idx. */
239 static bool verifyMethodDefiner(const CheckState* state, u4 definingClass,
241 const DexMethodId* meth = dexGetMethodId(state->pDexFile, methodIdx);
242 return meth->classIdx == definingClass;
246 * Calculate the required size (in elements) of the array pointed at by
249 static size_t calcDefinedClassBitsSize(const CheckState* state)
251 // Divide typeIdsSize by 32 (0x20), rounding up.
252 return (state->pHeader->typeIdsSize + 0x1f) >> 5;
256 * Set the given bit in pDefinedClassBits, returning its former value.
258 static bool setDefinedClassBit(const CheckState* state, u4 typeIdx) {
259 u4 arrayIdx = typeIdx >> 5;
260 u4 bit = 1 << (typeIdx & 0x1f);
261 u4* element = &state->pDefinedClassBits[arrayIdx];
262 bool result = (*element & bit) != 0;
270 * Swap the header_item.
272 static bool swapDexHeader(const CheckState* state, DexHeader* pHeader)
274 CHECK_PTR_RANGE(pHeader, pHeader + 1);
277 SWAP_FIELD4(pHeader->checksum);
279 SWAP_FIELD4(pHeader->fileSize);
280 SWAP_FIELD4(pHeader->headerSize);
281 SWAP_FIELD4(pHeader->endianTag);
282 SWAP_FIELD4(pHeader->linkSize);
283 SWAP_OFFSET4(pHeader->linkOff);
284 SWAP_OFFSET4(pHeader->mapOff);
285 SWAP_FIELD4(pHeader->stringIdsSize);
286 SWAP_OFFSET4(pHeader->stringIdsOff);
287 SWAP_FIELD4(pHeader->typeIdsSize);
288 SWAP_OFFSET4(pHeader->typeIdsOff);
289 SWAP_FIELD4(pHeader->fieldIdsSize);
290 SWAP_OFFSET4(pHeader->fieldIdsOff);
291 SWAP_FIELD4(pHeader->methodIdsSize);
292 SWAP_OFFSET4(pHeader->methodIdsOff);
293 SWAP_FIELD4(pHeader->protoIdsSize);
294 SWAP_OFFSET4(pHeader->protoIdsOff);
295 SWAP_FIELD4(pHeader->classDefsSize);
296 SWAP_OFFSET4(pHeader->classDefsOff);
297 SWAP_FIELD4(pHeader->dataSize);
298 SWAP_OFFSET4(pHeader->dataOff);
300 if (pHeader->endianTag != kDexEndianConstant) {
301 LOGE("Unexpected endian_tag: 0x%x\n", pHeader->endianTag);
305 // Assign variables so the diagnostic is prettier. (Hooray for macros.)
306 u4 linkOff = pHeader->linkOff;
307 u4 linkEnd = linkOff + pHeader->linkSize;
308 u4 dataOff = pHeader->dataOff;
309 u4 dataEnd = dataOff + pHeader->dataSize;
310 CHECK_OFFSET_RANGE(linkOff, linkEnd);
311 CHECK_OFFSET_RANGE(dataOff, dataEnd);
314 * Note: The offsets and ranges of the other header items end up getting
315 * checked during the first iteration over the map.
321 /* Check the header section for sanity. */
322 static bool checkHeaderSection(const CheckState* state, u4 sectionOffset,
323 u4 sectionCount, u4* endOffset) {
324 if (sectionCount != 1) {
325 LOGE("Multiple header items\n");
329 if (sectionOffset != 0) {
330 LOGE("Header at 0x%x; not at start of file\n", sectionOffset);
334 const DexHeader* pHeader = filePointer(state, 0);
335 *endOffset = pHeader->headerSize;
340 * Helper for swapMap(), which turns a map type constant into a small
341 * one-bit-on integer, suitable for use in an int-sized bit set.
343 static u4 mapTypeToBitMask(int mapType) {
345 case kDexTypeHeaderItem: return 1 << 0;
346 case kDexTypeStringIdItem: return 1 << 1;
347 case kDexTypeTypeIdItem: return 1 << 2;
348 case kDexTypeProtoIdItem: return 1 << 3;
349 case kDexTypeFieldIdItem: return 1 << 4;
350 case kDexTypeMethodIdItem: return 1 << 5;
351 case kDexTypeClassDefItem: return 1 << 6;
352 case kDexTypeMapList: return 1 << 7;
353 case kDexTypeTypeList: return 1 << 8;
354 case kDexTypeAnnotationSetRefList: return 1 << 9;
355 case kDexTypeAnnotationSetItem: return 1 << 10;
356 case kDexTypeClassDataItem: return 1 << 11;
357 case kDexTypeCodeItem: return 1 << 12;
358 case kDexTypeStringDataItem: return 1 << 13;
359 case kDexTypeDebugInfoItem: return 1 << 14;
360 case kDexTypeAnnotationItem: return 1 << 15;
361 case kDexTypeEncodedArrayItem: return 1 << 16;
362 case kDexTypeAnnotationsDirectoryItem: return 1 << 17;
364 LOGE("Unknown map item type %04x\n", mapType);
371 * Helper for swapMap(), which indicates if an item type should appear
372 * in the data section.
374 static bool isDataSectionType(int mapType) {
376 case kDexTypeHeaderItem:
377 case kDexTypeStringIdItem:
378 case kDexTypeTypeIdItem:
379 case kDexTypeProtoIdItem:
380 case kDexTypeFieldIdItem:
381 case kDexTypeMethodIdItem:
382 case kDexTypeClassDefItem: {
391 * Swap the map_list and verify what we can about it. Also, if verification
392 * passes, allocate the state's DexDataMap.
394 static bool swapMap(CheckState* state, DexMapList* pMap)
396 DexMapItem* item = pMap->list;
398 u4 dataItemCount = 0; // Total count of items in the data section.
399 u4 dataItemsLeft = state->pHeader->dataSize; // See use below.
400 u4 usedBits = 0; // Bit set: one bit per section
404 SWAP_FIELD4(pMap->size);
407 CHECK_LIST_SIZE(item, count, sizeof(DexMapItem));
410 SWAP_FIELD2(item->type);
411 SWAP_FIELD2(item->unused);
412 SWAP_FIELD4(item->size);
413 SWAP_OFFSET4(item->offset);
417 } else if (lastOffset >= item->offset) {
418 LOGE("Out-of-order map item: 0x%x then 0x%x\n",
419 lastOffset, item->offset);
423 if (item->offset >= state->pHeader->fileSize) {
424 LOGE("Map item after end of file: %x, size 0x%x\n",
425 item->offset, state->pHeader->fileSize);
429 if (isDataSectionType(item->type)) {
430 u4 icount = item->size;
433 * This sanity check on the data section items ensures that
434 * there are no more items than the number of bytes in
437 if (icount > dataItemsLeft) {
438 LOGE("Unrealistically many items in the data section: "
439 "at least %d\n", dataItemCount + icount);
443 dataItemsLeft -= icount;
444 dataItemCount += icount;
447 u4 bit = mapTypeToBitMask(item->type);
453 if ((usedBits & bit) != 0) {
454 LOGE("Duplicate map section of type 0x%x\n", item->type);
459 lastOffset = item->offset;
463 if ((usedBits & mapTypeToBitMask(kDexTypeHeaderItem)) == 0) {
464 LOGE("Map is missing header entry\n");
468 if ((usedBits & mapTypeToBitMask(kDexTypeMapList)) == 0) {
469 LOGE("Map is missing map_list entry\n");
473 if (((usedBits & mapTypeToBitMask(kDexTypeStringIdItem)) == 0)
474 && ((state->pHeader->stringIdsOff != 0)
475 || (state->pHeader->stringIdsSize != 0))) {
476 LOGE("Map is missing string_ids entry\n");
480 if (((usedBits & mapTypeToBitMask(kDexTypeTypeIdItem)) == 0)
481 && ((state->pHeader->typeIdsOff != 0)
482 || (state->pHeader->typeIdsSize != 0))) {
483 LOGE("Map is missing type_ids entry\n");
487 if (((usedBits & mapTypeToBitMask(kDexTypeProtoIdItem)) == 0)
488 && ((state->pHeader->protoIdsOff != 0)
489 || (state->pHeader->protoIdsSize != 0))) {
490 LOGE("Map is missing proto_ids entry\n");
494 if (((usedBits & mapTypeToBitMask(kDexTypeFieldIdItem)) == 0)
495 && ((state->pHeader->fieldIdsOff != 0)
496 || (state->pHeader->fieldIdsSize != 0))) {
497 LOGE("Map is missing field_ids entry\n");
501 if (((usedBits & mapTypeToBitMask(kDexTypeMethodIdItem)) == 0)
502 && ((state->pHeader->methodIdsOff != 0)
503 || (state->pHeader->methodIdsSize != 0))) {
504 LOGE("Map is missing method_ids entry\n");
508 if (((usedBits & mapTypeToBitMask(kDexTypeClassDefItem)) == 0)
509 && ((state->pHeader->classDefsOff != 0)
510 || (state->pHeader->classDefsSize != 0))) {
511 LOGE("Map is missing class_defs entry\n");
515 state->pDataMap = dexDataMapAlloc(dataItemCount);
516 if (state->pDataMap == NULL) {
517 LOGE("Unable to allocate data map (size 0x%x)\n", dataItemCount);
524 /* Check the map section for sanity. */
525 static bool checkMapSection(const CheckState* state, u4 sectionOffset,
526 u4 sectionCount, u4* endOffset) {
527 if (sectionCount != 1) {
528 LOGE("Multiple map list items");
532 if (sectionOffset != state->pHeader->mapOff) {
533 LOGE("Map not at header-defined offset: 0x%x, expected 0x%x\n",
534 sectionOffset, state->pHeader->mapOff);
538 const DexMapList* pMap = filePointer(state, sectionOffset);
541 sectionOffset + sizeof(u4) + (pMap->size * sizeof(DexMapItem));
545 /* Perform byte-swapping and intra-item verification on string_id_item. */
546 static void* swapStringIdItem(const CheckState* state, void* ptr) {
547 DexStringId* item = ptr;
549 CHECK_PTR_RANGE(item, item + 1);
550 SWAP_OFFSET4(item->stringDataOff);
555 /* Perform cross-item verification of string_id_item. */
556 static void* crossVerifyStringIdItem(const CheckState* state, void* ptr) {
557 const DexStringId* item = ptr;
559 if (!dexDataMapVerify(state->pDataMap,
560 item->stringDataOff, kDexTypeStringDataItem)) {
564 const DexStringId* item0 = state->previousItem;
567 const char* s0 = dexGetStringData(state->pDexFile, item0);
568 const char* s1 = dexGetStringData(state->pDexFile, item);
569 if (dexUtf8Cmp(s0, s1) >= 0) {
570 LOGE("Out-of-order string_ids: '%s' then '%s'\n", s0, s1);
575 return (void*) (item + 1);
578 /* Perform byte-swapping and intra-item verification on type_id_item. */
579 static void* swapTypeIdItem(const CheckState* state, void* ptr) {
580 DexTypeId* item = ptr;
582 CHECK_PTR_RANGE(item, item + 1);
583 SWAP_INDEX4(item->descriptorIdx, state->pHeader->stringIdsSize);
588 /* Perform cross-item verification of type_id_item. */
589 static void* crossVerifyTypeIdItem(const CheckState* state, void* ptr) {
590 const DexTypeId* item = ptr;
591 const char* descriptor =
592 dexStringById(state->pDexFile, item->descriptorIdx);
594 if (!dexIsValidTypeDescriptor(descriptor)) {
595 LOGE("Invalid type descriptor: '%s'\n", descriptor);
599 const DexTypeId* item0 = state->previousItem;
601 // Check ordering. This relies on string_ids being in order.
602 if (item0->descriptorIdx >= item->descriptorIdx) {
603 LOGE("Out-of-order type_ids: 0x%x then 0x%x\n",
604 item0->descriptorIdx, item->descriptorIdx);
609 return (void*) (item + 1);
612 /* Perform byte-swapping and intra-item verification on proto_id_item. */
613 static void* swapProtoIdItem(const CheckState* state, void* ptr) {
614 DexProtoId* item = ptr;
616 CHECK_PTR_RANGE(item, item + 1);
617 SWAP_INDEX4(item->shortyIdx, state->pHeader->stringIdsSize);
618 SWAP_INDEX4(item->returnTypeIdx, state->pHeader->typeIdsSize);
619 SWAP_OFFSET4(item->parametersOff);
624 /* Helper for crossVerifyProtoIdItem(), which checks a shorty character
625 * to see if it is compatible with a type descriptor. Returns true if
626 * so, false if not. */
627 static bool shortyDescMatch(char shorty, const char* descriptor, bool
632 LOGE("Invalid use of void\n");
645 if ((descriptor[0] != shorty) || (descriptor[1] != '\0')) {
646 LOGE("Shorty vs. primitive type mismatch: '%c', '%s'\n",
653 if ((descriptor[0] != 'L') && (descriptor[0] != '[')) {
654 LOGE("Shorty vs. type mismatch: '%c', '%s'\n",
661 LOGE("Bogus shorty: '%c'\n", shorty);
669 /* Perform cross-item verification of proto_id_item. */
670 static void* crossVerifyProtoIdItem(const CheckState* state, void* ptr) {
671 const DexProtoId* item = ptr;
673 dexStringById(state->pDexFile, item->shortyIdx);
675 if (!dexDataMapVerify0Ok(state->pDataMap,
676 item->parametersOff, kDexTypeTypeList)) {
680 if (!shortyDescMatch(*shorty,
681 dexStringByTypeIdx(state->pDexFile, item->returnTypeIdx),
686 u4 protoIdx = item - state->pDexFile->pProtoIds;
687 DexProto proto = { state->pDexFile, protoIdx };
688 DexParameterIterator iterator;
690 dexParameterIteratorInit(&iterator, &proto);
691 shorty++; // Skip the return type.
694 const char *desc = dexParameterIteratorNextDescriptor(&iterator);
700 if (*shorty == '\0') {
701 LOGE("Shorty is too short\n");
705 if (!shortyDescMatch(*shorty, desc, false)) {
712 if (*shorty != '\0') {
713 LOGE("Shorty is too long\n");
717 const DexProtoId* item0 = state->previousItem;
719 // Check ordering. This relies on type_ids being in order.
720 if (item0->returnTypeIdx > item->returnTypeIdx) {
721 LOGE("Out-of-order proto_id return types\n");
723 } else if (item0->returnTypeIdx == item->returnTypeIdx) {
724 bool badOrder = false;
725 DexProto proto0 = { state->pDexFile, protoIdx - 1 };
726 DexParameterIterator iterator0;
728 dexParameterIteratorInit(&iterator, &proto);
729 dexParameterIteratorInit(&iterator0, &proto0);
732 u4 idx0 = dexParameterIteratorNextIndex(&iterator0);
733 u4 idx1 = dexParameterIteratorNextIndex(&iterator);
735 if (idx1 == kDexNoIndex) {
740 if (idx0 == kDexNoIndex) {
746 } else if (idx0 > idx1) {
753 LOGE("Out-of-order proto_id arguments\n");
759 return (void*) (item + 1);
762 /* Perform byte-swapping and intra-item verification on field_id_item. */
763 static void* swapFieldIdItem(const CheckState* state, void* ptr) {
764 DexFieldId* item = ptr;
766 CHECK_PTR_RANGE(item, item + 1);
767 SWAP_INDEX2(item->classIdx, state->pHeader->typeIdsSize);
768 SWAP_INDEX2(item->typeIdx, state->pHeader->typeIdsSize);
769 SWAP_INDEX4(item->nameIdx, state->pHeader->stringIdsSize);
774 /* Perform cross-item verification of field_id_item. */
775 static void* crossVerifyFieldIdItem(const CheckState* state, void* ptr) {
776 const DexFieldId* item = ptr;
779 s = dexStringByTypeIdx(state->pDexFile, item->classIdx);
780 if (!dexIsClassDescriptor(s)) {
781 LOGE("Invalid descriptor for class_idx: '%s'\n", s);
785 s = dexStringByTypeIdx(state->pDexFile, item->typeIdx);
786 if (!dexIsFieldDescriptor(s)) {
787 LOGE("Invalid descriptor for type_idx: '%s'\n", s);
791 s = dexStringById(state->pDexFile, item->nameIdx);
792 if (!dexIsValidMemberName(s)) {
793 LOGE("Invalid name: '%s'\n", s);
797 const DexFieldId* item0 = state->previousItem;
799 // Check ordering. This relies on the other sections being in order.
803 if (item0->classIdx > item->classIdx) {
806 } else if (item0->classIdx < item->classIdx) {
811 if (item0->nameIdx > item->nameIdx) {
814 } else if (item0->nameIdx < item->nameIdx) {
820 if (item0->typeIdx >= item->typeIdx) {
826 LOGE("Out-of-order field_ids\n");
831 return (void*) (item + 1);
834 /* Perform byte-swapping and intra-item verification on method_id_item. */
835 static void* swapMethodIdItem(const CheckState* state, void* ptr) {
836 DexMethodId* item = ptr;
838 CHECK_PTR_RANGE(item, item + 1);
839 SWAP_INDEX2(item->classIdx, state->pHeader->typeIdsSize);
840 SWAP_INDEX2(item->protoIdx, state->pHeader->protoIdsSize);
841 SWAP_INDEX4(item->nameIdx, state->pHeader->stringIdsSize);
846 /* Perform cross-item verification of method_id_item. */
847 static void* crossVerifyMethodIdItem(const CheckState* state, void* ptr) {
848 const DexMethodId* item = ptr;
851 s = dexStringByTypeIdx(state->pDexFile, item->classIdx);
852 if (!dexIsReferenceDescriptor(s)) {
853 LOGE("Invalid descriptor for class_idx: '%s'\n", s);
857 s = dexStringById(state->pDexFile, item->nameIdx);
858 if (!dexIsValidMemberName(s)) {
859 LOGE("Invalid name: '%s'\n", s);
863 const DexMethodId* item0 = state->previousItem;
865 // Check ordering. This relies on the other sections being in order.
869 if (item0->classIdx > item->classIdx) {
872 } else if (item0->classIdx < item->classIdx) {
877 if (item0->nameIdx > item->nameIdx) {
880 } else if (item0->nameIdx < item->nameIdx) {
886 if (item0->protoIdx >= item->protoIdx) {
892 LOGE("Out-of-order method_ids\n");
897 return (void*) (item + 1);
900 /* Perform byte-swapping and intra-item verification on class_def_item. */
901 static void* swapClassDefItem(const CheckState* state, void* ptr) {
902 DexClassDef* item = ptr;
904 CHECK_PTR_RANGE(item, item + 1);
905 SWAP_INDEX4(item->classIdx, state->pHeader->typeIdsSize);
906 SWAP_FIELD4(item->accessFlags);
907 SWAP_INDEX4_OR_NOINDEX(item->superclassIdx, state->pHeader->typeIdsSize);
908 SWAP_OFFSET4(item->interfacesOff);
909 SWAP_INDEX4_OR_NOINDEX(item->sourceFileIdx, state->pHeader->stringIdsSize);
910 SWAP_OFFSET4(item->annotationsOff);
911 SWAP_OFFSET4(item->classDataOff);
917 static u4 findFirstClassDataDefiner(const CheckState* state,
918 DexClassData* classData);
919 static u4 findFirstAnnotationsDirectoryDefiner(const CheckState* state,
920 const DexAnnotationsDirectoryItem* dir);
922 /* Helper for crossVerifyClassDefItem(), which checks a class_data_item to
923 * make sure all its references are to a given class. */
924 static bool verifyClassDataIsForDef(const CheckState* state, u4 offset,
930 const u1* data = filePointer(state, offset);
931 DexClassData* classData = dexReadAndVerifyClassData(&data, NULL);
933 if (classData == NULL) {
934 // Shouldn't happen, but bail here just in case.
939 * The class_data_item verification ensures that
940 * it consistently refers to the same definer, so all we need to
941 * do is check the first one.
943 u4 dataDefiner = findFirstClassDataDefiner(state, classData);
944 bool result = (dataDefiner == definerIdx) || (dataDefiner == kDexNoIndex);
950 /* Helper for crossVerifyClassDefItem(), which checks an
951 * annotations_directory_item to make sure all its references are to a
953 static bool verifyAnnotationsDirectoryIsForDef(const CheckState* state,
954 u4 offset, u4 definerIdx) {
959 const DexAnnotationsDirectoryItem* dir = filePointer(state, offset);
960 u4 annoDefiner = findFirstAnnotationsDirectoryDefiner(state, dir);
962 return (annoDefiner == definerIdx) || (annoDefiner == kDexNoIndex);
965 /* Perform cross-item verification of class_def_item. */
966 static void* crossVerifyClassDefItem(const CheckState* state, void* ptr) {
967 const DexClassDef* item = ptr;
968 u4 classIdx = item->classIdx;
969 const char* descriptor = dexStringByTypeIdx(state->pDexFile, classIdx);
971 if (!dexIsClassDescriptor(descriptor)) {
972 LOGE("Invalid class: '%s'\n", descriptor);
976 if (setDefinedClassBit(state, classIdx)) {
977 LOGE("Duplicate class definition: '%s'\n", descriptor);
982 dexDataMapVerify0Ok(state->pDataMap,
983 item->interfacesOff, kDexTypeTypeList)
984 && dexDataMapVerify0Ok(state->pDataMap,
985 item->annotationsOff, kDexTypeAnnotationsDirectoryItem)
986 && dexDataMapVerify0Ok(state->pDataMap,
987 item->classDataOff, kDexTypeClassDataItem)
988 && dexDataMapVerify0Ok(state->pDataMap,
989 item->staticValuesOff, kDexTypeEncodedArrayItem);
995 if (item->superclassIdx != kDexNoIndex) {
996 descriptor = dexStringByTypeIdx(state->pDexFile, item->superclassIdx);
997 if (!dexIsClassDescriptor(descriptor)) {
998 LOGE("Invalid superclass: '%s'\n", descriptor);
1003 const DexTypeList* interfaces =
1004 dexGetInterfacesList(state->pDexFile, item);
1005 if (interfaces != NULL) {
1006 u4 size = interfaces->size;
1010 * Ensure that all interfaces refer to classes (not arrays or
1013 for (i = 0; i < size; i++) {
1014 descriptor = dexStringByTypeIdx(state->pDexFile,
1015 dexTypeListGetIdx(interfaces, i));
1016 if (!dexIsClassDescriptor(descriptor)) {
1017 LOGE("Invalid interface: '%s'\n", descriptor);
1023 * Ensure that there are no duplicates. This is an O(N^2) test,
1024 * but in practice the number of interfaces implemented by any
1025 * given class is low. I will buy a milkshake for the
1026 * first person to show me a realistic case for which this test
1027 * would be unacceptably slow.
1029 for (i = 1; i < size; i++) {
1030 u4 idx1 = dexTypeListGetIdx(interfaces, i);
1032 for (j = 0; j < i; j++) {
1033 u4 idx2 = dexTypeListGetIdx(interfaces, j);
1035 LOGE("Duplicate interface: '%s'\n",
1036 dexStringByTypeIdx(state->pDexFile, idx1));
1043 if (!verifyClassDataIsForDef(state, item->classDataOff, item->classIdx)) {
1044 LOGE("Invalid class_data_item\n");
1048 if (!verifyAnnotationsDirectoryIsForDef(state, item->annotationsOff,
1050 LOGE("Invalid annotations_directory_item\n");
1054 return (void*) (item + 1);
1057 /* Helper for swapAnnotationsDirectoryItem(), which performs
1058 * byte-swapping and intra-item verification on an
1059 * annotation_directory_item's field elements. */
1060 static u1* swapFieldAnnotations(const CheckState* state, u4 count, u1* addr) {
1061 DexFieldAnnotationsItem* item = (DexFieldAnnotationsItem*) addr;
1065 CHECK_LIST_SIZE(item, count, sizeof(DexFieldAnnotationsItem));
1068 SWAP_INDEX4(item->fieldIdx, state->pHeader->fieldIdsSize);
1069 SWAP_OFFSET4(item->annotationsOff);
1073 } else if (lastIdx >= item->fieldIdx) {
1074 LOGE("Out-of-order field_idx: 0x%x then 0x%x\n", lastIdx,
1079 lastIdx = item->fieldIdx;
1086 /* Helper for swapAnnotationsDirectoryItem(), which performs
1087 * byte-swapping and intra-item verification on an
1088 * annotation_directory_item's method elements. */
1089 static u1* swapMethodAnnotations(const CheckState* state, u4 count, u1* addr) {
1090 DexMethodAnnotationsItem* item = (DexMethodAnnotationsItem*) addr;
1094 CHECK_LIST_SIZE(item, count, sizeof(DexMethodAnnotationsItem));
1097 SWAP_INDEX4(item->methodIdx, state->pHeader->methodIdsSize);
1098 SWAP_OFFSET4(item->annotationsOff);
1102 } else if (lastIdx >= item->methodIdx) {
1103 LOGE("Out-of-order method_idx: 0x%x then 0x%x\n", lastIdx,
1108 lastIdx = item->methodIdx;
1115 /* Helper for swapAnnotationsDirectoryItem(), which performs
1116 * byte-swapping and intra-item verification on an
1117 * annotation_directory_item's parameter elements. */
1118 static u1* swapParameterAnnotations(const CheckState* state, u4 count,
1120 DexParameterAnnotationsItem* item = (DexParameterAnnotationsItem*) addr;
1124 CHECK_LIST_SIZE(item, count, sizeof(DexParameterAnnotationsItem));
1127 SWAP_INDEX4(item->methodIdx, state->pHeader->methodIdsSize);
1128 SWAP_OFFSET4(item->annotationsOff);
1132 } else if (lastIdx >= item->methodIdx) {
1133 LOGE("Out-of-order method_idx: 0x%x then 0x%x\n", lastIdx,
1138 lastIdx = item->methodIdx;
1145 /* Perform byte-swapping and intra-item verification on
1146 * annotations_directory_item. */
1147 static void* swapAnnotationsDirectoryItem(const CheckState* state, void* ptr) {
1148 DexAnnotationsDirectoryItem* item = ptr;
1150 CHECK_PTR_RANGE(item, item + 1);
1151 SWAP_OFFSET4(item->classAnnotationsOff);
1152 SWAP_FIELD4(item->fieldsSize);
1153 SWAP_FIELD4(item->methodsSize);
1154 SWAP_FIELD4(item->parametersSize);
1156 u1* addr = (u1*) (item + 1);
1158 if (item->fieldsSize != 0) {
1159 addr = swapFieldAnnotations(state, item->fieldsSize, addr);
1165 if (item->methodsSize != 0) {
1166 addr = swapMethodAnnotations(state, item->methodsSize, addr);
1172 if (item->parametersSize != 0) {
1173 addr = swapParameterAnnotations(state, item->parametersSize, addr);
1182 /* Helper for crossVerifyAnnotationsDirectoryItem(), which checks the
1183 * field elements. */
1184 static const u1* crossVerifyFieldAnnotations(const CheckState* state, u4 count,
1185 const u1* addr, u4 definingClass) {
1186 const DexFieldAnnotationsItem* item = (DexFieldAnnotationsItem*) addr;
1189 if (!verifyFieldDefiner(state, definingClass, item->fieldIdx)) {
1192 if (!dexDataMapVerify(state->pDataMap, item->annotationsOff,
1193 kDexTypeAnnotationSetItem)) {
1199 return (const u1*) item;
1202 /* Helper for crossVerifyAnnotationsDirectoryItem(), which checks the
1203 * method elements. */
1204 static const u1* crossVerifyMethodAnnotations(const CheckState* state,
1205 u4 count, const u1* addr, u4 definingClass) {
1206 const DexMethodAnnotationsItem* item = (DexMethodAnnotationsItem*) addr;
1209 if (!verifyMethodDefiner(state, definingClass, item->methodIdx)) {
1212 if (!dexDataMapVerify(state->pDataMap, item->annotationsOff,
1213 kDexTypeAnnotationSetItem)) {
1219 return (const u1*) item;
1222 /* Helper for crossVerifyAnnotationsDirectoryItem(), which checks the
1223 * parameter elements. */
1224 static const u1* crossVerifyParameterAnnotations(const CheckState* state,
1225 u4 count, const u1* addr, u4 definingClass) {
1226 const DexParameterAnnotationsItem* item =
1227 (DexParameterAnnotationsItem*) addr;
1230 if (!verifyMethodDefiner(state, definingClass, item->methodIdx)) {
1233 if (!dexDataMapVerify(state->pDataMap, item->annotationsOff,
1234 kDexTypeAnnotationSetRefList)) {
1240 return (const u1*) item;
1243 /* Helper for crossVerifyClassDefItem() and
1244 * crossVerifyAnnotationsDirectoryItem(), which finds the type_idx of
1245 * the definer of the first item in the data. */
1246 static u4 findFirstAnnotationsDirectoryDefiner(const CheckState* state,
1247 const DexAnnotationsDirectoryItem* dir) {
1248 if (dir->fieldsSize != 0) {
1249 const DexFieldAnnotationsItem* fields =
1250 dexGetFieldAnnotations(state->pDexFile, dir);
1251 const DexFieldId* field =
1252 dexGetFieldId(state->pDexFile, fields[0].fieldIdx);
1253 return field->classIdx;
1256 if (dir->methodsSize != 0) {
1257 const DexMethodAnnotationsItem* methods =
1258 dexGetMethodAnnotations(state->pDexFile, dir);
1259 const DexMethodId* method =
1260 dexGetMethodId(state->pDexFile, methods[0].methodIdx);
1261 return method->classIdx;
1264 if (dir->parametersSize != 0) {
1265 const DexParameterAnnotationsItem* parameters =
1266 dexGetParameterAnnotations(state->pDexFile, dir);
1267 const DexMethodId* method =
1268 dexGetMethodId(state->pDexFile, parameters[0].methodIdx);
1269 return method->classIdx;
1275 /* Perform cross-item verification of annotations_directory_item. */
1276 static void* crossVerifyAnnotationsDirectoryItem(const CheckState* state,
1278 const DexAnnotationsDirectoryItem* item = ptr;
1279 u4 definingClass = findFirstAnnotationsDirectoryDefiner(state, item);
1281 if (!dexDataMapVerify0Ok(state->pDataMap,
1282 item->classAnnotationsOff, kDexTypeAnnotationSetItem)) {
1286 const u1* addr = (const u1*) (item + 1);
1288 if (item->fieldsSize != 0) {
1289 addr = crossVerifyFieldAnnotations(state, item->fieldsSize, addr,
1296 if (item->methodsSize != 0) {
1297 addr = crossVerifyMethodAnnotations(state, item->methodsSize, addr,
1304 if (item->parametersSize != 0) {
1305 addr = crossVerifyParameterAnnotations(state, item->parametersSize,
1306 addr, definingClass);
1312 return (void*) addr;
1315 /* Perform byte-swapping and intra-item verification on type_list. */
1316 static void* swapTypeList(const CheckState* state, void* ptr)
1318 DexTypeList* pTypeList = ptr;
1322 CHECK_PTR_RANGE(pTypeList, pTypeList + 1);
1323 SWAP_FIELD4(pTypeList->size);
1324 count = pTypeList->size;
1325 pType = pTypeList->list;
1326 CHECK_LIST_SIZE(pType, count, sizeof(DexTypeItem));
1329 SWAP_INDEX2(pType->typeIdx, state->pHeader->typeIdsSize);
1336 /* Perform byte-swapping and intra-item verification on
1337 * annotation_set_ref_list. */
1338 static void* swapAnnotationSetRefList(const CheckState* state, void* ptr) {
1339 DexAnnotationSetRefList* list = ptr;
1340 DexAnnotationSetRefItem* item;
1343 CHECK_PTR_RANGE(list, list + 1);
1344 SWAP_FIELD4(list->size);
1347 CHECK_LIST_SIZE(item, count, sizeof(DexAnnotationSetRefItem));
1350 SWAP_OFFSET4(item->annotationsOff);
1357 /* Perform cross-item verification of annotation_set_ref_list. */
1358 static void* crossVerifyAnnotationSetRefList(const CheckState* state,
1360 const DexAnnotationSetRefList* list = ptr;
1361 const DexAnnotationSetRefItem* item = list->list;
1362 int count = list->size;
1365 if (!dexDataMapVerify0Ok(state->pDataMap,
1366 item->annotationsOff, kDexTypeAnnotationSetItem)) {
1372 return (void*) item;
1375 /* Perform byte-swapping and intra-item verification on
1376 * annotation_set_item. */
1377 static void* swapAnnotationSetItem(const CheckState* state, void* ptr) {
1378 DexAnnotationSetItem* set = ptr;
1382 CHECK_PTR_RANGE(set, set + 1);
1383 SWAP_FIELD4(set->size);
1385 item = set->entries;
1386 CHECK_LIST_SIZE(item, count, sizeof(u4));
1389 SWAP_OFFSET4(*item);
1396 /* Helper for crossVerifyAnnotationSetItem(), which extracts the type_idx
1397 * out of an annotation_item. */
1398 static u4 annotationItemTypeIdx(const DexAnnotationItem* item) {
1399 const u1* data = item->annotation;
1400 return readUnsignedLeb128(&data);
1403 /* Perform cross-item verification of annotation_set_item. */
1404 static void* crossVerifyAnnotationSetItem(const CheckState* state, void* ptr) {
1405 const DexAnnotationSetItem* set = ptr;
1406 int count = set->size;
1411 for (i = 0; i < count; i++) {
1412 if (!dexDataMapVerify0Ok(state->pDataMap,
1413 dexGetAnnotationOff(set, i), kDexTypeAnnotationItem)) {
1417 const DexAnnotationItem* annotation =
1418 dexGetAnnotationItem(state->pDexFile, set, i);
1419 u4 idx = annotationItemTypeIdx(annotation);
1423 } else if (lastIdx >= idx) {
1424 LOGE("Out-of-order entry types: 0x%x then 0x%x\n",
1432 return (void*) (set->entries + count);
1435 /* Helper for verifyClassDataItem(), which checks a list of fields. */
1436 static bool verifyFields(const CheckState* state, u4 size,
1437 DexField* fields, bool expectStatic) {
1440 for (i = 0; i < size; i++) {
1441 DexField* field = &fields[i];
1442 u4 accessFlags = field->accessFlags;
1443 bool isStatic = (accessFlags & ACC_STATIC) != 0;
1445 CHECK_INDEX(field->fieldIdx, state->pHeader->fieldIdsSize);
1447 if (isStatic != expectStatic) {
1448 LOGE("Field in wrong list @ %d\n", i);
1452 if ((accessFlags & ~ACC_FIELD_MASK) != 0) {
1453 LOGE("Bogus field access flags %x @ %d\n", accessFlags, i);
1461 /* Helper for verifyClassDataItem(), which checks a list of methods. */
1462 static bool verifyMethods(const CheckState* state, u4 size,
1463 DexMethod* methods, bool expectDirect) {
1466 for (i = 0; i < size; i++) {
1467 DexMethod* method = &methods[i];
1469 CHECK_INDEX(method->methodIdx, state->pHeader->methodIdsSize);
1471 u4 accessFlags = method->accessFlags;
1473 (accessFlags & (ACC_STATIC | ACC_PRIVATE | ACC_CONSTRUCTOR)) != 0;
1474 bool expectCode = (accessFlags & (ACC_NATIVE | ACC_ABSTRACT)) == 0;
1475 bool isSynchronized = (accessFlags & ACC_SYNCHRONIZED) != 0;
1476 bool allowSynchronized = (accessFlags & ACC_NATIVE) != 0;
1478 if (isDirect != expectDirect) {
1479 LOGE("Method in wrong list @ %d\n", i);
1483 if (((accessFlags & ~ACC_METHOD_MASK) != 0)
1484 || (isSynchronized && !allowSynchronized)) {
1485 LOGE("Bogus method access flags %x @ %d\n", accessFlags, i);
1490 if (method->codeOff == 0) {
1491 LOGE("Unexpected zero code_off for access_flags %x\n",
1495 } else if (method->codeOff != 0) {
1496 LOGE("Unexpected non-zero code_off 0x%x for access_flags %x\n",
1497 method->codeOff, accessFlags);
1505 /* Helper for verifyClassDataItem(), which does most of the work. */
1506 static bool verifyClassDataItem0(const CheckState* state,
1507 DexClassData* classData) {
1510 okay = verifyFields(state, classData->header.staticFieldsSize,
1511 classData->staticFields, true);
1514 LOGE("Trouble with static fields\n");
1518 verifyFields(state, classData->header.instanceFieldsSize,
1519 classData->instanceFields, false);
1522 LOGE("Trouble with instance fields\n");
1526 okay = verifyMethods(state, classData->header.directMethodsSize,
1527 classData->directMethods, true);
1530 LOGE("Trouble with direct methods\n");
1534 okay = verifyMethods(state, classData->header.virtualMethodsSize,
1535 classData->virtualMethods, false);
1538 LOGE("Trouble with virtual methods\n");
1545 /* Perform intra-item verification on class_data_item. */
1546 static void* intraVerifyClassDataItem(const CheckState* state, void* ptr) {
1547 const u1* data = ptr;
1548 DexClassData* classData = dexReadAndVerifyClassData(&data, state->fileEnd);
1550 if (classData == NULL) {
1551 LOGE("Unable to parse class_data_item\n");
1555 bool okay = verifyClassDataItem0(state, classData);
1563 return (void*) data;
1566 /* Helper for crossVerifyClassDefItem() and
1567 * crossVerifyClassDataItem(), which finds the type_idx of the definer
1568 * of the first item in the data. */
1569 static u4 findFirstClassDataDefiner(const CheckState* state,
1570 DexClassData* classData) {
1571 if (classData->header.staticFieldsSize != 0) {
1572 u4 fieldIdx = classData->staticFields[0].fieldIdx;
1573 const DexFieldId* field = dexGetFieldId(state->pDexFile, fieldIdx);
1574 return field->classIdx;
1577 if (classData->header.instanceFieldsSize != 0) {
1578 u4 fieldIdx = classData->instanceFields[0].fieldIdx;
1579 const DexFieldId* field = dexGetFieldId(state->pDexFile, fieldIdx);
1580 return field->classIdx;
1583 if (classData->header.directMethodsSize != 0) {
1584 u4 methodIdx = classData->directMethods[0].methodIdx;
1585 const DexMethodId* meth = dexGetMethodId(state->pDexFile, methodIdx);
1586 return meth->classIdx;
1589 if (classData->header.virtualMethodsSize != 0) {
1590 u4 methodIdx = classData->virtualMethods[0].methodIdx;
1591 const DexMethodId* meth = dexGetMethodId(state->pDexFile, methodIdx);
1592 return meth->classIdx;
1598 /* Perform cross-item verification of class_data_item. */
1599 static void* crossVerifyClassDataItem(const CheckState* state, void* ptr) {
1600 const u1* data = ptr;
1601 DexClassData* classData = dexReadAndVerifyClassData(&data, state->fileEnd);
1602 u4 definingClass = findFirstClassDataDefiner(state, classData);
1606 for (i = classData->header.staticFieldsSize; okay && (i > 0); /*i*/) {
1608 const DexField* field = &classData->staticFields[i];
1609 okay = verifyFieldDefiner(state, definingClass, field->fieldIdx);
1612 for (i = classData->header.instanceFieldsSize; okay && (i > 0); /*i*/) {
1614 const DexField* field = &classData->instanceFields[i];
1615 okay = verifyFieldDefiner(state, definingClass, field->fieldIdx);
1618 for (i = classData->header.directMethodsSize; okay && (i > 0); /*i*/) {
1620 const DexMethod* meth = &classData->directMethods[i];
1621 okay = dexDataMapVerify0Ok(state->pDataMap, meth->codeOff,
1623 && verifyMethodDefiner(state, definingClass, meth->methodIdx);
1626 for (i = classData->header.virtualMethodsSize; okay && (i > 0); /*i*/) {
1628 const DexMethod* meth = &classData->virtualMethods[i];
1629 okay = dexDataMapVerify0Ok(state->pDataMap, meth->codeOff,
1631 && verifyMethodDefiner(state, definingClass, meth->methodIdx);
1640 return (void*) data;
1643 /* Helper for swapCodeItem(), which fills an array with all the valid
1644 * handlerOff values for catch handlers and also verifies the handler
1646 static u4 setHandlerOffsAndVerify(const CheckState* state,
1647 DexCode* code, u4 firstOffset, u4 handlersSize, u4* handlerOffs) {
1648 const u1* fileEnd = state->fileEnd;
1649 const u1* handlersBase = dexGetCatchHandlerData(code);
1650 u4 offset = firstOffset;
1654 for (i = 0; i < handlersSize; i++) {
1655 const u1* ptr = handlersBase + offset;
1656 int size = readAndVerifySignedLeb128(&ptr, fileEnd, &okay);
1660 LOGE("Bogus size\n");
1664 if ((size < -65536) || (size > 65536)) {
1665 LOGE("Invalid size: %d\n", size);
1676 handlerOffs[i] = offset;
1678 while (size-- > 0) {
1680 readAndVerifyUnsignedLeb128(&ptr, fileEnd, &okay);
1683 LOGE("Bogus type_idx");
1687 CHECK_INDEX(typeIdx, state->pHeader->typeIdsSize);
1689 u4 addr = readAndVerifyUnsignedLeb128(&ptr, fileEnd, &okay);
1696 if (addr >= code->insnsSize) {
1697 LOGE("Invalid addr: 0x%x", addr);
1703 u4 addr = readAndVerifyUnsignedLeb128(&ptr, fileEnd, &okay);
1706 LOGE("Bogus catch_all_addr");
1710 if (addr >= code->insnsSize) {
1711 LOGE("Invalid catch_all_addr: 0x%x", addr);
1716 offset = ptr - handlersBase;
1722 /* Helper for swapCodeItem(), which does all the try-catch related
1723 * swapping and verification. */
1724 static void* swapTriesAndCatches(const CheckState* state, DexCode* code) {
1725 const u1* encodedHandlers = dexGetCatchHandlerData(code);
1726 const u1* encodedPtr = encodedHandlers;
1729 readAndVerifyUnsignedLeb128(&encodedPtr, state->fileEnd, &okay);
1732 LOGE("Bogus handlers_size\n");
1736 if ((handlersSize == 0) || (handlersSize >= 65536)) {
1737 LOGE("Invalid handlers_size: %d\n", handlersSize);
1741 u4 handlerOffs[handlersSize]; // list of valid handlerOff values
1742 u4 endOffset = setHandlerOffsAndVerify(state, code,
1743 encodedPtr - encodedHandlers,
1744 handlersSize, handlerOffs);
1746 if (endOffset == 0) {
1750 DexTry* tries = (DexTry*) dexGetTries(code);
1751 u4 count = code->triesSize;
1754 CHECK_LIST_SIZE(tries, count, sizeof(DexTry));
1759 SWAP_FIELD4(tries->startAddr);
1760 SWAP_FIELD2(tries->insnCount);
1761 SWAP_FIELD2(tries->handlerOff);
1763 if (tries->startAddr < lastEnd) {
1764 LOGE("Out-of-order try\n");
1768 if (tries->startAddr >= code->insnsSize) {
1769 LOGE("Invalid start_addr: 0x%x\n", tries->startAddr);
1773 for (i = 0; i < handlersSize; i++) {
1774 if (tries->handlerOff == handlerOffs[i]) {
1779 if (i == handlersSize) {
1780 LOGE("Bogus handler offset: 0x%x\n", tries->handlerOff);
1784 lastEnd = tries->startAddr + tries->insnCount;
1786 if (lastEnd > code->insnsSize) {
1787 LOGE("Invalid insn_count: 0x%x (end addr 0x%x)\n",
1788 tries->insnCount, lastEnd);
1795 return (u1*) encodedHandlers + endOffset;
1798 /* Perform byte-swapping and intra-item verification on code_item. */
1799 static void* swapCodeItem(const CheckState* state, void* ptr) {
1800 DexCode* item = ptr;
1804 CHECK_PTR_RANGE(item, item + 1);
1805 SWAP_FIELD2(item->registersSize);
1806 SWAP_FIELD2(item->insSize);
1807 SWAP_FIELD2(item->outsSize);
1808 SWAP_FIELD2(item->triesSize);
1809 SWAP_OFFSET4(item->debugInfoOff);
1810 SWAP_FIELD4(item->insnsSize);
1812 if (item->insSize > item->registersSize) {
1813 LOGE("insSize (%u) > registersSize (%u)\n", item->insSize,
1814 item->registersSize);
1818 if ((item->outsSize > 5) && (item->outsSize > item->registersSize)) {
1820 * It's okay for outsSize to be up to five, even if registersSize
1821 * is smaller, since the short forms of method invocation allow
1822 * repetition of a register multiple times within a single parameter
1823 * list. Longer parameter lists, though, need to be represented
1824 * in-order in the register file.
1826 LOGE("outsSize (%u) > registersSize (%u)\n", item->outsSize,
1827 item->registersSize);
1831 count = item->insnsSize;
1832 insns = item->insns;
1833 CHECK_LIST_SIZE(insns, count, sizeof(u2));
1836 *insns = SWAP2(*insns);
1840 if (item->triesSize == 0) {
1843 if ((((u4) insns) & 3) != 0) {
1844 // Four-byte alignment for the tries. Verify the spacer is a 0.
1846 LOGE("Non-zero padding: 0x%x\n", (u4) *insns);
1851 ptr = swapTriesAndCatches(state, item);
1857 /* Perform intra-item verification on string_data_item. */
1858 static void* intraVerifyStringDataItem(const CheckState* state, void* ptr) {
1859 const u1* fileEnd = state->fileEnd;
1860 const u1* data = ptr;
1862 u4 utf16Size = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
1866 LOGE("Bogus utf16_size\n");
1870 for (i = 0; i < utf16Size; i++) {
1871 if (data >= fileEnd) {
1872 LOGE("String data would go beyond end-of-file\n");
1876 u1 byte1 = *(data++);
1878 // Switch on the high four bits.
1879 switch (byte1 >> 4) {
1881 // Special case of bit pattern 0xxx.
1883 LOGE("String shorter than indicated utf16_size 0x%x\n",
1896 // Bit pattern 0xxx. No need for any extra bytes or checks.
1905 * Bit pattern 10xx or 1111, which are illegal start bytes.
1906 * Note: 1111 is valid for normal UTF-8, but not the
1907 * modified UTF-8 used here.
1909 LOGE("Illegal start byte 0x%x\n", byte1);
1913 // Bit pattern 1110, so there are two additional bytes.
1914 u1 byte2 = *(data++);
1915 if ((byte2 & 0xc0) != 0x80) {
1916 LOGE("Illegal continuation byte 0x%x\n", byte2);
1919 u1 byte3 = *(data++);
1920 if ((byte3 & 0xc0) != 0x80) {
1921 LOGE("Illegal continuation byte 0x%x\n", byte3);
1924 u2 value = ((byte1 & 0x0f) << 12) | ((byte2 & 0x3f) << 6)
1926 if (value < 0x800) {
1927 LOGE("Illegal representation for value %x\n", value);
1934 // Bit pattern 110x, so there is one additional byte.
1935 u1 byte2 = *(data++);
1936 if ((byte2 & 0xc0) != 0x80) {
1937 LOGE("Illegal continuation byte 0x%x\n", byte2);
1940 u2 value = ((byte1 & 0x1f) << 6) | (byte2 & 0x3f);
1941 if ((value != 0) && (value < 0x80)) {
1942 LOGE("Illegal representation for value %x\n", value);
1950 if (*(data++) != '\0') {
1951 LOGE("String longer than indicated utf16_size 0x%x\n", utf16Size);
1955 return (void*) data;
1958 /* Perform intra-item verification on debug_info_item. */
1959 static void* intraVerifyDebugInfoItem(const CheckState* state, void* ptr) {
1960 const u1* fileEnd = state->fileEnd;
1961 const u1* data = ptr;
1965 readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
1968 LOGE("Bogus line_start\n");
1973 readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
1976 LOGE("Bogus parameters_size\n");
1980 if (parametersSize > 65536) {
1981 LOGE("Invalid parameters_size: 0x%x\n", parametersSize);
1985 for (i = 0; i < parametersSize; i++) {
1987 readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
1990 LOGE("Bogus parameter_name\n");
1994 if (parameterName != 0) {
1996 CHECK_INDEX(parameterName, state->pHeader->stringIdsSize);
2002 u1 opcode = *(data++);
2005 case DBG_END_SEQUENCE: {
2009 case DBG_ADVANCE_PC: {
2010 readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2013 case DBG_ADVANCE_LINE: {
2014 readAndVerifySignedLeb128(&data, fileEnd, &okay);
2017 case DBG_START_LOCAL: {
2019 u4 regNum = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2021 if (regNum >= 65536) {
2025 idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2029 CHECK_INDEX(idx, state->pHeader->stringIdsSize);
2031 idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2035 CHECK_INDEX(idx, state->pHeader->stringIdsSize);
2040 case DBG_RESTART_LOCAL: {
2041 u4 regNum = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2043 if (regNum >= 65536) {
2049 case DBG_START_LOCAL_EXTENDED: {
2051 u4 regNum = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2053 if (regNum >= 65536) {
2057 idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2061 CHECK_INDEX(idx, state->pHeader->stringIdsSize);
2063 idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2067 CHECK_INDEX(idx, state->pHeader->stringIdsSize);
2069 idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2073 CHECK_INDEX(idx, state->pHeader->stringIdsSize);
2077 case DBG_SET_FILE: {
2078 u4 idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2082 CHECK_INDEX(idx, state->pHeader->stringIdsSize);
2087 // No arguments to parse for anything else.
2092 LOGE("Bogus syntax for opcode %02x\n", opcode);
2097 return (void*) data;
2101 static const u1* verifyEncodedValue(const CheckState* state, const u1* data,
2103 static const u1* verifyEncodedAnnotation(const CheckState* state,
2104 const u1* data, bool crossVerify);
2106 /* Helper for verifyEncodedValue(), which reads a 1- to 4- byte unsigned
2107 * little endian value. */
2108 static u4 readUnsignedLittleEndian(const CheckState* state, const u1** pData,
2110 const u1* data = *pData;
2114 CHECK_PTR_RANGE(data, data + size);
2116 for (i = 0; i < size; i++) {
2117 result |= ((u4) *(data++)) << (i * 8);
2124 /* Helper for *VerifyAnnotationItem() and *VerifyEncodedArrayItem(), which
2125 * verifies an encoded_array. */
2126 static const u1* verifyEncodedArray(const CheckState* state,
2127 const u1* data, bool crossVerify) {
2129 u4 size = readAndVerifyUnsignedLeb128(&data, state->fileEnd, &okay);
2132 LOGE("Bogus encoded_array size\n");
2137 data = verifyEncodedValue(state, data, crossVerify);
2139 LOGE("Bogus encoded_array value\n");
2147 /* Helper for *VerifyAnnotationItem() and *VerifyEncodedArrayItem(), which
2148 * verifies an encoded_value. */
2149 static const u1* verifyEncodedValue(const CheckState* state,
2150 const u1* data, bool crossVerify) {
2151 CHECK_PTR_RANGE(data, data + 1);
2153 u1 headerByte = *(data++);
2154 u4 valueType = headerByte & kDexAnnotationValueTypeMask;
2155 u4 valueArg = headerByte >> kDexAnnotationValueArgShift;
2157 switch (valueType) {
2158 case kDexAnnotationByte: {
2159 if (valueArg != 0) {
2160 LOGE("Bogus byte size 0x%x\n", valueArg);
2166 case kDexAnnotationShort:
2167 case kDexAnnotationChar: {
2169 LOGE("Bogus char/short size 0x%x\n", valueArg);
2172 data += valueArg + 1;
2175 case kDexAnnotationInt:
2176 case kDexAnnotationFloat: {
2178 LOGE("Bogus int/float size 0x%x\n", valueArg);
2181 data += valueArg + 1;
2184 case kDexAnnotationLong:
2185 case kDexAnnotationDouble: {
2186 data += valueArg + 1;
2189 case kDexAnnotationString: {
2191 LOGE("Bogus string size 0x%x\n", valueArg);
2194 u4 idx = readUnsignedLittleEndian(state, &data, valueArg + 1);
2195 CHECK_INDEX(idx, state->pHeader->stringIdsSize);
2198 case kDexAnnotationType: {
2200 LOGE("Bogus type size 0x%x\n", valueArg);
2203 u4 idx = readUnsignedLittleEndian(state, &data, valueArg + 1);
2204 CHECK_INDEX(idx, state->pHeader->typeIdsSize);
2207 case kDexAnnotationField:
2208 case kDexAnnotationEnum: {
2210 LOGE("Bogus field/enum size 0x%x\n", valueArg);
2213 u4 idx = readUnsignedLittleEndian(state, &data, valueArg + 1);
2214 CHECK_INDEX(idx, state->pHeader->fieldIdsSize);
2217 case kDexAnnotationMethod: {
2219 LOGE("Bogus method size 0x%x\n", valueArg);
2222 u4 idx = readUnsignedLittleEndian(state, &data, valueArg + 1);
2223 CHECK_INDEX(idx, state->pHeader->methodIdsSize);
2226 case kDexAnnotationArray: {
2227 if (valueArg != 0) {
2228 LOGE("Bogus array value_arg 0x%x\n", valueArg);
2231 data = verifyEncodedArray(state, data, crossVerify);
2234 case kDexAnnotationAnnotation: {
2235 if (valueArg != 0) {
2236 LOGE("Bogus annotation value_arg 0x%x\n", valueArg);
2239 data = verifyEncodedAnnotation(state, data, crossVerify);
2242 case kDexAnnotationNull: {
2243 if (valueArg != 0) {
2244 LOGE("Bogus null value_arg 0x%x\n", valueArg);
2247 // Nothing else to do for this type.
2250 case kDexAnnotationBoolean: {
2252 LOGE("Bogus boolean value_arg 0x%x\n", valueArg);
2255 // Nothing else to do for this type.
2259 LOGE("Bogus value_type 0x%x\n", valueType);
2267 /* Helper for *VerifyAnnotationItem() and *VerifyEncodedArrayItem(), which
2268 * verifies an encoded_annotation. */
2269 static const u1* verifyEncodedAnnotation(const CheckState* state,
2270 const u1* data, bool crossVerify) {
2271 const u1* fileEnd = state->fileEnd;
2273 u4 idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2276 LOGE("Bogus encoded_annotation type_idx\n");
2280 CHECK_INDEX(idx, state->pHeader->typeIdsSize);
2283 const char* descriptor = dexStringByTypeIdx(state->pDexFile, idx);
2284 if (!dexIsClassDescriptor(descriptor)) {
2285 LOGE("Bogus annotation type: '%s'\n", descriptor);
2290 u4 size = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2295 LOGE("Bogus encoded_annotation size\n");
2300 idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2303 LOGE("Bogus encoded_annotation name_idx\n");
2307 CHECK_INDEX(idx, state->pHeader->stringIdsSize);
2310 const char* name = dexStringById(state->pDexFile, idx);
2311 if (!dexIsValidMemberName(name)) {
2312 LOGE("Bogus annotation member name: '%s'\n", name);
2319 } else if (lastIdx >= idx) {
2320 LOGE("Out-of-order encoded_annotation name_idx: 0x%x then 0x%x\n",
2325 data = verifyEncodedValue(state, data, crossVerify);
2336 /* Perform intra-item verification on encoded_array_item. */
2337 static void* intraVerifyEncodedArrayItem(const CheckState* state, void* ptr) {
2338 return (void*) verifyEncodedArray(state, (const u1*) ptr, false);
2341 /* Perform intra-item verification on annotation_item. */
2342 static void* intraVerifyAnnotationItem(const CheckState* state, void* ptr) {
2343 const u1* data = ptr;
2345 CHECK_PTR_RANGE(data, data + 1);
2347 switch (*(data++)) {
2348 case kDexVisibilityBuild:
2349 case kDexVisibilityRuntime:
2350 case kDexVisibilitySystem: {
2354 LOGE("Bogus annotation visibility: 0x%x\n", *data);
2359 return (void*) verifyEncodedAnnotation(state, data, false);
2362 /* Perform cross-item verification on annotation_item. */
2363 static void* crossVerifyAnnotationItem(const CheckState* state, void* ptr) {
2364 const u1* data = ptr;
2366 // Skip the visibility byte.
2369 return (void*) verifyEncodedAnnotation(state, data, true);
2376 * Function to visit an individual top-level item type.
2378 typedef void* ItemVisitorFunction(const CheckState* state, void* ptr);
2381 * Iterate over all the items in a section, optionally updating the
2382 * data map (done if mapType is passed as non-negative). The section
2383 * must consist of concatenated items of the same type.
2385 static bool iterateSectionWithOptionalUpdate(CheckState* state,
2386 u4 offset, u4 count, ItemVisitorFunction* func, u4 alignment,
2387 u4* nextOffset, int mapType) {
2388 u4 alignmentMask = alignment - 1;
2391 state->previousItem = NULL;
2393 for (i = 0; i < count; i++) {
2394 u4 newOffset = (offset + alignmentMask) & ~alignmentMask;
2395 u1* ptr = filePointer(state, newOffset);
2397 if (offset < newOffset) {
2398 ptr = filePointer(state, offset);
2399 if (offset < newOffset) {
2400 CHECK_OFFSET_RANGE(offset, newOffset);
2401 while (offset < newOffset) {
2403 LOGE("Non-zero padding 0x%02x @ %x\n", *ptr, offset);
2412 u1* newPtr = (u1*) func(state, ptr);
2413 newOffset = fileOffset(state, newPtr);
2415 if (newPtr == NULL) {
2416 LOGE("Trouble with item %d @ offset 0x%x\n", i, offset);
2420 if (newOffset > state->fileLen) {
2421 LOGE("Item %d @ offset 0x%x ends out of bounds\n", i, offset);
2426 dexDataMapAdd(state->pDataMap, offset, mapType);
2429 state->previousItem = ptr;
2433 if (nextOffset != NULL) {
2434 *nextOffset = offset;
2441 * Iterate over all the items in a section. The section must consist of
2442 * concatenated items of the same type. This variant will not update the data
2445 static bool iterateSection(CheckState* state, u4 offset, u4 count,
2446 ItemVisitorFunction* func, u4 alignment, u4* nextOffset) {
2447 return iterateSectionWithOptionalUpdate(state, offset, count, func,
2448 alignment, nextOffset, -1);
2452 * Like iterateSection(), but also check that the offset and count match
2453 * a given pair of expected values.
2455 static bool checkBoundsAndIterateSection(CheckState* state,
2456 u4 offset, u4 count, u4 expectedOffset, u4 expectedCount,
2457 ItemVisitorFunction* func, u4 alignment, u4* nextOffset) {
2458 if (offset != expectedOffset) {
2459 LOGE("Bogus offset for section: got 0x%x; expected 0x%x\n",
2460 offset, expectedOffset);
2464 if (count != expectedCount) {
2465 LOGE("Bogus size for section: got 0x%x; expected 0x%x\n",
2466 count, expectedCount);
2470 return iterateSection(state, offset, count, func, alignment, nextOffset);
2474 * Like iterateSection(), but also update the data section map and
2475 * check that all the items fall within the data section.
2477 static bool iterateDataSection(CheckState* state, u4 offset, u4 count,
2478 ItemVisitorFunction* func, u4 alignment, u4* nextOffset, int mapType) {
2479 u4 dataStart = state->pHeader->dataOff;
2480 u4 dataEnd = dataStart + state->pHeader->dataSize;
2482 assert(nextOffset != NULL);
2484 if ((offset < dataStart) || (offset >= dataEnd)) {
2485 LOGE("Bogus offset for data subsection: 0x%x\n", offset);
2489 if (!iterateSectionWithOptionalUpdate(state, offset, count, func,
2490 alignment, nextOffset, mapType)) {
2494 if (*nextOffset > dataEnd) {
2495 LOGE("Out-of-bounds end of data subsection: 0x%x\n", *nextOffset);
2503 * Byte-swap all items in the given map except the header and the map
2504 * itself, both of which should have already gotten swapped. This also
2505 * does all possible intra-item verification, that is, verification
2506 * that doesn't need to assume the sanctity of the contents of *other*
2507 * items. The intra-item limitation is because at the time an item is
2508 * asked to verify itself, it can't assume that the items it refers to
2509 * have been byte-swapped and verified.
2511 static bool swapEverythingButHeaderAndMap(CheckState* state,
2513 const DexMapItem* item = pMap->list;
2515 u4 count = pMap->size;
2518 while (okay && count--) {
2519 u4 sectionOffset = item->offset;
2520 u4 sectionCount = item->size;
2521 u2 type = item->type;
2523 if (lastOffset < sectionOffset) {
2524 CHECK_OFFSET_RANGE(lastOffset, sectionOffset);
2525 const u1* ptr = filePointer(state, lastOffset);
2526 while (lastOffset < sectionOffset) {
2528 LOGE("Non-zero padding 0x%02x before section start @ %x\n",
2536 } else if (lastOffset > sectionOffset) {
2537 LOGE("Section overlap or out-of-order map: %x, %x\n",
2538 lastOffset, sectionOffset);
2547 case kDexTypeHeaderItem: {
2549 * The header got swapped very early on, but do some
2550 * additional sanity checking here.
2552 okay = checkHeaderSection(state, sectionOffset, sectionCount,
2556 case kDexTypeStringIdItem: {
2557 okay = checkBoundsAndIterateSection(state, sectionOffset,
2558 sectionCount, state->pHeader->stringIdsOff,
2559 state->pHeader->stringIdsSize, swapStringIdItem,
2560 sizeof(u4), &lastOffset);
2563 case kDexTypeTypeIdItem: {
2564 okay = checkBoundsAndIterateSection(state, sectionOffset,
2565 sectionCount, state->pHeader->typeIdsOff,
2566 state->pHeader->typeIdsSize, swapTypeIdItem,
2567 sizeof(u4), &lastOffset);
2570 case kDexTypeProtoIdItem: {
2571 okay = checkBoundsAndIterateSection(state, sectionOffset,
2572 sectionCount, state->pHeader->protoIdsOff,
2573 state->pHeader->protoIdsSize, swapProtoIdItem,
2574 sizeof(u4), &lastOffset);
2577 case kDexTypeFieldIdItem: {
2578 okay = checkBoundsAndIterateSection(state, sectionOffset,
2579 sectionCount, state->pHeader->fieldIdsOff,
2580 state->pHeader->fieldIdsSize, swapFieldIdItem,
2581 sizeof(u4), &lastOffset);
2584 case kDexTypeMethodIdItem: {
2585 okay = checkBoundsAndIterateSection(state, sectionOffset,
2586 sectionCount, state->pHeader->methodIdsOff,
2587 state->pHeader->methodIdsSize, swapMethodIdItem,
2588 sizeof(u4), &lastOffset);
2591 case kDexTypeClassDefItem: {
2592 okay = checkBoundsAndIterateSection(state, sectionOffset,
2593 sectionCount, state->pHeader->classDefsOff,
2594 state->pHeader->classDefsSize, swapClassDefItem,
2595 sizeof(u4), &lastOffset);
2598 case kDexTypeMapList: {
2600 * The map section was swapped early on, but do some
2601 * additional sanity checking here.
2603 okay = checkMapSection(state, sectionOffset, sectionCount,
2607 case kDexTypeTypeList: {
2608 okay = iterateDataSection(state, sectionOffset, sectionCount,
2609 swapTypeList, sizeof(u4), &lastOffset, type);
2612 case kDexTypeAnnotationSetRefList: {
2613 okay = iterateDataSection(state, sectionOffset, sectionCount,
2614 swapAnnotationSetRefList, sizeof(u4), &lastOffset,
2618 case kDexTypeAnnotationSetItem: {
2619 okay = iterateDataSection(state, sectionOffset, sectionCount,
2620 swapAnnotationSetItem, sizeof(u4), &lastOffset, type);
2623 case kDexTypeClassDataItem: {
2624 okay = iterateDataSection(state, sectionOffset, sectionCount,
2625 intraVerifyClassDataItem, sizeof(u1), &lastOffset,
2629 case kDexTypeCodeItem: {
2630 okay = iterateDataSection(state, sectionOffset, sectionCount,
2631 swapCodeItem, sizeof(u4), &lastOffset, type);
2634 case kDexTypeStringDataItem: {
2635 okay = iterateDataSection(state, sectionOffset, sectionCount,
2636 intraVerifyStringDataItem, sizeof(u1), &lastOffset,
2640 case kDexTypeDebugInfoItem: {
2641 okay = iterateDataSection(state, sectionOffset, sectionCount,
2642 intraVerifyDebugInfoItem, sizeof(u1), &lastOffset,
2646 case kDexTypeAnnotationItem: {
2647 okay = iterateDataSection(state, sectionOffset, sectionCount,
2648 intraVerifyAnnotationItem, sizeof(u1), &lastOffset,
2652 case kDexTypeEncodedArrayItem: {
2653 okay = iterateDataSection(state, sectionOffset, sectionCount,
2654 intraVerifyEncodedArrayItem, sizeof(u1), &lastOffset,
2658 case kDexTypeAnnotationsDirectoryItem: {
2659 okay = iterateDataSection(state, sectionOffset, sectionCount,
2660 swapAnnotationsDirectoryItem, sizeof(u4), &lastOffset,
2665 LOGE("Unknown map item type %04x\n", type);
2671 LOGE("Swap of section type %04x failed\n", type);
2681 * Perform cross-item verification on everything that needs it. This
2682 * pass is only called after all items are byte-swapped and
2683 * intra-verified (checked for internal consistency).
2685 static bool crossVerifyEverything(CheckState* state, DexMapList* pMap)
2687 const DexMapItem* item = pMap->list;
2688 u4 count = pMap->size;
2691 while (okay && count--) {
2692 u4 sectionOffset = item->offset;
2693 u4 sectionCount = item->size;
2695 switch (item->type) {
2696 case kDexTypeHeaderItem:
2697 case kDexTypeMapList:
2698 case kDexTypeTypeList:
2699 case kDexTypeCodeItem:
2700 case kDexTypeStringDataItem:
2701 case kDexTypeDebugInfoItem:
2702 case kDexTypeAnnotationItem:
2703 case kDexTypeEncodedArrayItem: {
2704 // There is no need for cross-item verification for these.
2707 case kDexTypeStringIdItem: {
2708 okay = iterateSection(state, sectionOffset, sectionCount,
2709 crossVerifyStringIdItem, sizeof(u4), NULL);
2712 case kDexTypeTypeIdItem: {
2713 okay = iterateSection(state, sectionOffset, sectionCount,
2714 crossVerifyTypeIdItem, sizeof(u4), NULL);
2717 case kDexTypeProtoIdItem: {
2718 okay = iterateSection(state, sectionOffset, sectionCount,
2719 crossVerifyProtoIdItem, sizeof(u4), NULL);
2722 case kDexTypeFieldIdItem: {
2723 okay = iterateSection(state, sectionOffset, sectionCount,
2724 crossVerifyFieldIdItem, sizeof(u4), NULL);
2727 case kDexTypeMethodIdItem: {
2728 okay = iterateSection(state, sectionOffset, sectionCount,
2729 crossVerifyMethodIdItem, sizeof(u4), NULL);
2732 case kDexTypeClassDefItem: {
2733 // Allocate (on the stack) the "observed class_def" bits.
2734 size_t arraySize = calcDefinedClassBitsSize(state);
2735 u4 definedClassBits[arraySize];
2736 memset(definedClassBits, 0, arraySize * sizeof(u4));
2737 state->pDefinedClassBits = definedClassBits;
2739 okay = iterateSection(state, sectionOffset, sectionCount,
2740 crossVerifyClassDefItem, sizeof(u4), NULL);
2742 state->pDefinedClassBits = NULL;
2745 case kDexTypeAnnotationSetRefList: {
2746 okay = iterateSection(state, sectionOffset, sectionCount,
2747 crossVerifyAnnotationSetRefList, sizeof(u4), NULL);
2750 case kDexTypeAnnotationSetItem: {
2751 okay = iterateSection(state, sectionOffset, sectionCount,
2752 crossVerifyAnnotationSetItem, sizeof(u4), NULL);
2755 case kDexTypeClassDataItem: {
2756 okay = iterateSection(state, sectionOffset, sectionCount,
2757 crossVerifyClassDataItem, sizeof(u1), NULL);
2760 case kDexTypeAnnotationsDirectoryItem: {
2761 okay = iterateSection(state, sectionOffset, sectionCount,
2762 crossVerifyAnnotationsDirectoryItem, sizeof(u4), NULL);
2766 LOGE("Unknown map item type %04x\n", item->type);
2772 LOGE("Cross-item verify of section type %04x failed\n",
2783 * Fix the byte ordering of all fields in the DEX file, and do
2784 * structural verification. This is only required for code that opens
2785 * "raw" DEX files, such as the DEX optimizer.
2787 * Returns 0 on success, nonzero on failure.
2789 int dexSwapAndVerify(u1* addr, int len)
2795 memset(&state, 0, sizeof(state));
2796 LOGV("+++ swapping and verifying\n");
2799 * Start by verifying the magic number. The caller verified that "len"
2800 * says we have at least a header's worth of data.
2802 pHeader = (DexHeader*) addr;
2803 if (memcmp(pHeader->magic, DEX_MAGIC, 4) != 0) {
2804 /* really shouldn't be here -- this is weird */
2805 LOGE("ERROR: Can't byte swap: bad magic number "
2806 "(0x%02x %02x %02x %02x)\n",
2807 pHeader->magic[0], pHeader->magic[1],
2808 pHeader->magic[2], pHeader->magic[3]);
2812 if (okay && memcmp(pHeader->magic+4, DEX_MAGIC_VERS, 4) != 0) {
2813 /* older or newer version we don't know how to read */
2814 LOGE("ERROR: Can't byte swap: bad dex version "
2815 "(0x%02x %02x %02x %02x)\n",
2816 pHeader->magic[4], pHeader->magic[5],
2817 pHeader->magic[6], pHeader->magic[7]);
2822 int expectedLen = (int) SWAP4(pHeader->fileSize);
2823 if (len < expectedLen) {
2824 LOGE("ERROR: Bad length: expected %d, got %d\n", expectedLen, len);
2826 } else if (len != expectedLen) {
2827 LOGW("WARNING: Odd length: expected %d, got %d\n", expectedLen,
2835 * Compute the adler32 checksum and compare it to what's stored in
2836 * the file. This isn't free, but chances are good that we just
2837 * unpacked this from a jar file and have all of the pages sitting
2838 * in memory, so it's pretty quick.
2840 * This might be a big-endian system, so we need to do this before
2841 * we byte-swap the header.
2843 uLong adler = adler32(0L, Z_NULL, 0);
2844 const int nonSum = sizeof(pHeader->magic) + sizeof(pHeader->checksum);
2845 u4 storedFileSize = SWAP4(pHeader->fileSize);
2846 u4 expectedChecksum = SWAP4(pHeader->checksum);
2848 adler = adler32(adler, ((const u1*) pHeader) + nonSum,
2849 storedFileSize - nonSum);
2851 if (adler != expectedChecksum) {
2852 LOGE("ERROR: bad checksum (%08lx, expected %08x)\n",
2853 adler, expectedChecksum);
2859 state.fileStart = addr;
2860 state.fileEnd = addr + len;
2861 state.fileLen = len;
2862 state.pDexFile = NULL;
2863 state.pDataMap = NULL;
2864 state.pDefinedClassBits = NULL;
2865 state.previousItem = NULL;
2868 * Swap the header and check the contents.
2870 okay = swapDexHeader(&state, pHeader);
2874 state.pHeader = pHeader;
2876 if (pHeader->headerSize < sizeof(DexHeader)) {
2877 LOGE("ERROR: Small header size %d, struct %d\n",
2878 pHeader->headerSize, (int) sizeof(DexHeader));
2880 } else if (pHeader->headerSize > sizeof(DexHeader)) {
2881 LOGW("WARNING: Large header size %d, struct %d\n",
2882 pHeader->headerSize, (int) sizeof(DexHeader));
2889 * Look for the map. Swap it and then use it to find and swap
2892 if (pHeader->mapOff != 0) {
2894 DexMapList* pDexMap = (DexMapList*) (addr + pHeader->mapOff);
2896 okay = okay && swapMap(&state, pDexMap);
2897 okay = okay && swapEverythingButHeaderAndMap(&state, pDexMap);
2899 dexFileSetupBasicPointers(&dexFile, addr);
2900 state.pDexFile = &dexFile;
2902 okay = okay && crossVerifyEverything(&state, pDexMap);
2904 LOGE("ERROR: No map found; impossible to byte-swap and verify");
2910 LOGE("ERROR: Byte swap + verify failed\n");
2913 if (state.pDataMap != NULL) {
2914 dexDataMapFree(state.pDataMap);
2917 return !okay; // 0 == success
2921 * Detect the file type of the given memory buffer via magic number.
2922 * Call dexSwapAndVerify() on an unoptimized DEX file, do nothing
2923 * but return successfully on an optimized DEX file, and report an
2924 * error for all other cases.
2926 * Returns 0 on success, nonzero on failure.
2928 int dexSwapAndVerifyIfNecessary(u1* addr, int len)
2930 if (memcmp(addr, DEX_OPT_MAGIC, 4) == 0) {
2931 // It is an optimized dex file.
2935 if (memcmp(addr, DEX_MAGIC, 4) == 0) {
2936 // It is an unoptimized dex file.
2937 return dexSwapAndVerify(addr, len);
2940 LOGE("ERROR: Bad magic number (0x%02x %02x %02x %02x)\n",
2941 addr[0], addr[1], addr[2], addr[3]);