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"
35 # error "byte ordering not defined"
38 #if __BYTE_ORDER == __LITTLE_ENDIAN
39 # define SWAP2(_value) (_value)
40 # define SWAP4(_value) (_value)
41 # define SWAP8(_value) (_value)
43 # define SWAP2(_value) endianSwapU2((_value))
44 # define SWAP4(_value) endianSwapU4((_value))
45 # define SWAP8(_value) endianSwapU8((_value))
46 static u2 endianSwapU2(u2 value) {
47 return (value >> 8) | (value << 8);
49 static u4 endianSwapU4(u4 value) {
50 /* ABCD --> CDAB --> DCBA */
51 value = (value >> 16) | (value << 16);
52 return ((value & 0xff00ff00) >> 8) | ((value << 8) & 0xff00ff00);
54 static u8 endianSwapU8(u8 value) {
55 /* ABCDEFGH --> EFGHABCD --> GHEFCDAB --> HGFEDCBA */
56 value = (value >> 32) | (value << 32);
57 value = ((value & 0xffff0000ffff0000ULL) >> 16) |
58 ((value << 16) & 0xffff0000ffff0000ULL);
59 return ((value & 0xff00ff00ff00ff00ULL) >> 8) |
60 ((value << 8) & 0xff00ff00ff00ff00ULL);
64 #define SWAP_FIELD2(_field) (_field) = SWAP2(_field)
65 #define SWAP_FIELD4(_field) (_field) = SWAP4(_field)
66 #define SWAP_FIELD8(_field) (_field) = SWAP8(_field)
69 * Some information we pass around to help verify values.
72 const DexHeader* pHeader;
74 const u1* fileEnd; // points to fileStart + fileLen
76 DexDataMap* pDataMap; // set after map verification
77 const DexFile* pDexFile; // set after intraitem verification
80 * bitmap of type_id indices that have been used to define classes;
81 * initialized immediately before class_def cross-verification, and
82 * freed immediately after it
84 u4* pDefinedClassBits;
86 const void* previousItem; // set during section iteration
90 * Return the file offset of the given pointer.
92 static inline u4 fileOffset(const CheckState* state, const void* ptr) {
93 return ((const u1*) ptr) - state->fileStart;
97 * Return a pointer for the given file offset.
99 static inline void* filePointer(const CheckState* state, u4 offset) {
100 return (void*) (state->fileStart + offset);
104 * Verify that a pointer range, start inclusive to end exclusive, only
105 * covers bytes in the file and doesn't point beyond the end of the
106 * file. That is, the start must indicate a valid byte or may point at
107 * the byte just past the end of the file (but no further), and the
108 * end must be no less than the start and must also not point beyond
109 * the byte just past the end of the file.
111 static inline bool checkPtrRange(const CheckState* state,
112 const void* start, const void* end, const char* label) {
113 const void* fileStart = state->fileStart;
114 const void* fileEnd = state->fileEnd;
115 if ((start < fileStart) || (start > fileEnd)
116 || (end < start) || (end > fileEnd)) {
117 ALOGW("Bad offset range for %s: %#x..%#x", label,
118 fileOffset(state, start), fileOffset(state, end));
125 * Verify that a range of offsets, start inclusive to end exclusive,
126 * are all valid. That is, the start must indicate a valid byte or may
127 * point at the byte just past the end of the file (but no further),
128 * and the end must be no less than the start and must also not point
129 * beyond the byte just past the end of the file.
131 * Assumes "const CheckState* state".
133 #define CHECK_OFFSET_RANGE(_start, _end) { \
134 const u1* _startPtr = (const u1*) filePointer(state, (_start)); \
135 const u1* _endPtr = (const u1*) filePointer(state, (_end)); \
136 if (!checkPtrRange(state, _startPtr, _endPtr, \
137 #_start ".." #_end)) { \
143 * Verify that a pointer range, start inclusive to end exclusive, only
144 * covers bytes in the file and doesn't point beyond the end of the
145 * file. That is, the start must indicate a valid byte or may point at
146 * the byte just past the end of the file (but no further), and the
147 * end must be no less than the start and must also not point beyond
148 * the byte just past the end of the file.
150 * Assumes "const CheckState* state".
152 #define CHECK_PTR_RANGE(_start, _end) { \
153 if (!checkPtrRange(state, (_start), (_end), #_start ".." #_end)) { \
159 * Make sure a list of items fits entirely within the file.
161 * Assumes "const CheckState* state" and "typeof(_count) == typeof(_elemSize)"
162 * If the type sizes or signs are mismatched, this will return 0.
164 #define CHECK_LIST_SIZE(_ptr, _count, _elemSize) { \
165 const u1* _start = (const u1*) (_ptr); \
166 const u1* _end = _start + ((_count) * (_elemSize)); \
167 if (!safe_mul(NULL, (_count), (_elemSize)) || \
168 !checkPtrRange(state, _start, _end, #_ptr)) { \
174 * Swap a field that is known to hold an absolute DEX file offset. Note:
175 * This does not check to see that the swapped offset points within the
176 * mapped file, since that should be handled (with even more rigor) by
177 * the cross-verification phase.
179 * Assumes "const CheckState* state".
181 #define SWAP_OFFSET4(_field) { \
182 SWAP_FIELD4((_field)); \
186 * Verify that an index falls in a valid range.
188 #define CHECK_INDEX(_field, _limit) { \
189 if ((_field) >= (_limit)) { \
190 ALOGW("Bad index: %s(%u) > %s(%u)", \
191 #_field, (u4)(_field), #_limit, (u4)(_limit)); \
197 * Swap an index, and verify that it falls in a valid range.
199 #define SWAP_INDEX2(_field, _limit) { \
200 SWAP_FIELD2((_field)); \
201 CHECK_INDEX((_field), (_limit)); \
205 * Verify that an index falls in a valid range or is kDexNoIndex.
207 #define CHECK_INDEX_OR_NOINDEX(_field, _limit) { \
208 if ((_field) != kDexNoIndex && (_field) >= (_limit)) { \
209 ALOGW("Bad index: %s(%u) > %s(%u)", \
210 #_field, (u4)(_field), #_limit, (u4)(_limit)); \
216 * Swap an index, and verify that it falls in a valid range.
218 #define SWAP_INDEX4(_field, _limit) { \
219 SWAP_FIELD4((_field)); \
220 CHECK_INDEX((_field), (_limit)); \
224 * Swap an index, and verify that it falls in a valid range or is
227 #define SWAP_INDEX4_OR_NOINDEX(_field, _limit) { \
228 SWAP_FIELD4((_field)); \
229 CHECK_INDEX_OR_NOINDEX((_field), (_limit)); \
232 /* Verify the definer of a given field_idx. */
233 static bool verifyFieldDefiner(const CheckState* state, u4 definingClass,
235 const DexFieldId* field = dexGetFieldId(state->pDexFile, fieldIdx);
236 return field->classIdx == definingClass;
239 /* Verify the definer of a given method_idx. */
240 static bool verifyMethodDefiner(const CheckState* state, u4 definingClass,
242 const DexMethodId* meth = dexGetMethodId(state->pDexFile, methodIdx);
243 return meth->classIdx == definingClass;
247 * Calculate the required size (in elements) of the array pointed at by
250 static size_t calcDefinedClassBitsSize(const CheckState* state)
252 // Divide typeIdsSize by 32 (0x20), rounding up.
253 return (state->pHeader->typeIdsSize + 0x1f) >> 5;
257 * Set the given bit in pDefinedClassBits, returning its former value.
259 static bool setDefinedClassBit(const CheckState* state, u4 typeIdx) {
260 u4 arrayIdx = typeIdx >> 5;
261 u4 bit = 1 << (typeIdx & 0x1f);
262 u4* element = &state->pDefinedClassBits[arrayIdx];
263 bool result = (*element & bit) != 0;
271 * Swap the header_item.
273 static bool swapDexHeader(const CheckState* state, DexHeader* pHeader)
275 CHECK_PTR_RANGE(pHeader, pHeader + 1);
278 SWAP_FIELD4(pHeader->checksum);
280 SWAP_FIELD4(pHeader->fileSize);
281 SWAP_FIELD4(pHeader->headerSize);
282 SWAP_FIELD4(pHeader->endianTag);
283 SWAP_FIELD4(pHeader->linkSize);
284 SWAP_OFFSET4(pHeader->linkOff);
285 SWAP_OFFSET4(pHeader->mapOff);
286 SWAP_FIELD4(pHeader->stringIdsSize);
287 SWAP_OFFSET4(pHeader->stringIdsOff);
288 SWAP_FIELD4(pHeader->typeIdsSize);
289 SWAP_OFFSET4(pHeader->typeIdsOff);
290 SWAP_FIELD4(pHeader->fieldIdsSize);
291 SWAP_OFFSET4(pHeader->fieldIdsOff);
292 SWAP_FIELD4(pHeader->methodIdsSize);
293 SWAP_OFFSET4(pHeader->methodIdsOff);
294 SWAP_FIELD4(pHeader->protoIdsSize);
295 SWAP_OFFSET4(pHeader->protoIdsOff);
296 SWAP_FIELD4(pHeader->classDefsSize);
297 SWAP_OFFSET4(pHeader->classDefsOff);
298 SWAP_FIELD4(pHeader->dataSize);
299 SWAP_OFFSET4(pHeader->dataOff);
301 if (pHeader->endianTag != kDexEndianConstant) {
302 ALOGE("Unexpected endian_tag: %#x", pHeader->endianTag);
306 // Assign variables so the diagnostic is prettier. (Hooray for macros.)
307 u4 linkOff = pHeader->linkOff;
308 u4 linkEnd = linkOff + pHeader->linkSize;
309 u4 dataOff = pHeader->dataOff;
310 u4 dataEnd = dataOff + pHeader->dataSize;
311 CHECK_OFFSET_RANGE(linkOff, linkEnd);
312 CHECK_OFFSET_RANGE(dataOff, dataEnd);
315 * Note: The offsets and ranges of the other header items end up getting
316 * checked during the first iteration over the map.
322 /* Check the header section for sanity. */
323 static bool checkHeaderSection(const CheckState* state, u4 sectionOffset,
324 u4 sectionCount, u4* endOffset) {
325 if (sectionCount != 1) {
326 ALOGE("Multiple header items");
330 if (sectionOffset != 0) {
331 ALOGE("Header at %#x; not at start of file", sectionOffset);
335 const DexHeader* pHeader = (const DexHeader*) filePointer(state, 0);
336 *endOffset = pHeader->headerSize;
341 * Helper for swapMap(), which turns a map type constant into a small
342 * one-bit-on integer, suitable for use in an int-sized bit set.
344 static u4 mapTypeToBitMask(int mapType) {
346 case kDexTypeHeaderItem: return 1 << 0;
347 case kDexTypeStringIdItem: return 1 << 1;
348 case kDexTypeTypeIdItem: return 1 << 2;
349 case kDexTypeProtoIdItem: return 1 << 3;
350 case kDexTypeFieldIdItem: return 1 << 4;
351 case kDexTypeMethodIdItem: return 1 << 5;
352 case kDexTypeClassDefItem: return 1 << 6;
353 case kDexTypeMapList: return 1 << 7;
354 case kDexTypeTypeList: return 1 << 8;
355 case kDexTypeAnnotationSetRefList: return 1 << 9;
356 case kDexTypeAnnotationSetItem: return 1 << 10;
357 case kDexTypeClassDataItem: return 1 << 11;
358 case kDexTypeCodeItem: return 1 << 12;
359 case kDexTypeStringDataItem: return 1 << 13;
360 case kDexTypeDebugInfoItem: return 1 << 14;
361 case kDexTypeAnnotationItem: return 1 << 15;
362 case kDexTypeEncodedArrayItem: return 1 << 16;
363 case kDexTypeAnnotationsDirectoryItem: return 1 << 17;
365 ALOGE("Unknown map item type %04x", mapType);
372 * Helper for swapMap(), which indicates if an item type should appear
373 * in the data section.
375 static bool isDataSectionType(int mapType) {
377 case kDexTypeHeaderItem:
378 case kDexTypeStringIdItem:
379 case kDexTypeTypeIdItem:
380 case kDexTypeProtoIdItem:
381 case kDexTypeFieldIdItem:
382 case kDexTypeMethodIdItem:
383 case kDexTypeClassDefItem: {
392 * Swap the map_list and verify what we can about it. Also, if verification
393 * passes, allocate the state's DexDataMap.
395 static bool swapMap(CheckState* state, DexMapList* pMap)
397 DexMapItem* item = pMap->list;
399 u4 dataItemCount = 0; // Total count of items in the data section.
400 u4 dataItemsLeft = state->pHeader->dataSize; // See use below.
401 u4 usedBits = 0; // Bit set: one bit per section
405 SWAP_FIELD4(pMap->size);
408 CHECK_LIST_SIZE(item, count, sizeof(DexMapItem));
411 SWAP_FIELD2(item->type);
412 SWAP_FIELD2(item->unused);
413 SWAP_FIELD4(item->size);
414 SWAP_OFFSET4(item->offset);
418 } else if (lastOffset >= item->offset) {
419 ALOGE("Out-of-order map item: %#x then %#x",
420 lastOffset, item->offset);
424 if (item->offset >= state->pHeader->fileSize) {
425 ALOGE("Map item after end of file: %x, size %#x",
426 item->offset, state->pHeader->fileSize);
430 if (isDataSectionType(item->type)) {
431 u4 icount = item->size;
434 * This sanity check on the data section items ensures that
435 * there are no more items than the number of bytes in
438 if (icount > dataItemsLeft) {
439 ALOGE("Unrealistically many items in the data section: "
440 "at least %d", dataItemCount + icount);
444 dataItemsLeft -= icount;
445 dataItemCount += icount;
448 u4 bit = mapTypeToBitMask(item->type);
454 if ((usedBits & bit) != 0) {
455 ALOGE("Duplicate map section of type %#x", item->type);
460 lastOffset = item->offset;
464 if ((usedBits & mapTypeToBitMask(kDexTypeHeaderItem)) == 0) {
465 ALOGE("Map is missing header entry");
469 if ((usedBits & mapTypeToBitMask(kDexTypeMapList)) == 0) {
470 ALOGE("Map is missing map_list entry");
474 if (((usedBits & mapTypeToBitMask(kDexTypeStringIdItem)) == 0)
475 && ((state->pHeader->stringIdsOff != 0)
476 || (state->pHeader->stringIdsSize != 0))) {
477 ALOGE("Map is missing string_ids entry");
481 if (((usedBits & mapTypeToBitMask(kDexTypeTypeIdItem)) == 0)
482 && ((state->pHeader->typeIdsOff != 0)
483 || (state->pHeader->typeIdsSize != 0))) {
484 ALOGE("Map is missing type_ids entry");
488 if (((usedBits & mapTypeToBitMask(kDexTypeProtoIdItem)) == 0)
489 && ((state->pHeader->protoIdsOff != 0)
490 || (state->pHeader->protoIdsSize != 0))) {
491 ALOGE("Map is missing proto_ids entry");
495 if (((usedBits & mapTypeToBitMask(kDexTypeFieldIdItem)) == 0)
496 && ((state->pHeader->fieldIdsOff != 0)
497 || (state->pHeader->fieldIdsSize != 0))) {
498 ALOGE("Map is missing field_ids entry");
502 if (((usedBits & mapTypeToBitMask(kDexTypeMethodIdItem)) == 0)
503 && ((state->pHeader->methodIdsOff != 0)
504 || (state->pHeader->methodIdsSize != 0))) {
505 ALOGE("Map is missing method_ids entry");
509 if (((usedBits & mapTypeToBitMask(kDexTypeClassDefItem)) == 0)
510 && ((state->pHeader->classDefsOff != 0)
511 || (state->pHeader->classDefsSize != 0))) {
512 ALOGE("Map is missing class_defs entry");
516 state->pDataMap = dexDataMapAlloc(dataItemCount);
517 if (state->pDataMap == NULL) {
518 ALOGE("Unable to allocate data map (size %#x)", dataItemCount);
525 /* Check the map section for sanity. */
526 static bool checkMapSection(const CheckState* state, u4 sectionOffset,
527 u4 sectionCount, u4* endOffset) {
528 if (sectionCount != 1) {
529 ALOGE("Multiple map list items");
533 if (sectionOffset != state->pHeader->mapOff) {
534 ALOGE("Map not at header-defined offset: %#x, expected %#x",
535 sectionOffset, state->pHeader->mapOff);
539 const DexMapList* pMap = (const DexMapList*) filePointer(state, sectionOffset);
542 sectionOffset + sizeof(u4) + (pMap->size * sizeof(DexMapItem));
546 /* Perform byte-swapping and intra-item verification on string_id_item. */
547 static void* swapStringIdItem(const CheckState* state, void* ptr) {
548 DexStringId* item = (DexStringId*) ptr;
550 CHECK_PTR_RANGE(item, item + 1);
551 SWAP_OFFSET4(item->stringDataOff);
556 /* Perform cross-item verification of string_id_item. */
557 static void* crossVerifyStringIdItem(const CheckState* state, void* ptr) {
558 const DexStringId* item = (const DexStringId*) ptr;
560 if (!dexDataMapVerify(state->pDataMap,
561 item->stringDataOff, kDexTypeStringDataItem)) {
565 const DexStringId* item0 = (const DexStringId*) state->previousItem;
568 const char* s0 = dexGetStringData(state->pDexFile, item0);
569 const char* s1 = dexGetStringData(state->pDexFile, item);
570 if (dexUtf8Cmp(s0, s1) >= 0) {
571 ALOGE("Out-of-order string_ids: '%s' then '%s'", s0, s1);
576 return (void*) (item + 1);
579 /* Perform byte-swapping and intra-item verification on type_id_item. */
580 static void* swapTypeIdItem(const CheckState* state, void* ptr) {
581 DexTypeId* item = (DexTypeId*) ptr;
583 CHECK_PTR_RANGE(item, item + 1);
584 SWAP_INDEX4(item->descriptorIdx, state->pHeader->stringIdsSize);
589 /* Perform cross-item verification of type_id_item. */
590 static void* crossVerifyTypeIdItem(const CheckState* state, void* ptr) {
591 const DexTypeId* item = (const DexTypeId*) ptr;
592 const char* descriptor =
593 dexStringById(state->pDexFile, item->descriptorIdx);
595 if (!dexIsValidTypeDescriptor(descriptor)) {
596 ALOGE("Invalid type descriptor: '%s'", descriptor);
600 const DexTypeId* item0 = (const DexTypeId*) state->previousItem;
602 // Check ordering. This relies on string_ids being in order.
603 if (item0->descriptorIdx >= item->descriptorIdx) {
604 ALOGE("Out-of-order type_ids: %#x then %#x",
605 item0->descriptorIdx, item->descriptorIdx);
610 return (void*) (item + 1);
613 /* Perform byte-swapping and intra-item verification on proto_id_item. */
614 static void* swapProtoIdItem(const CheckState* state, void* ptr) {
615 DexProtoId* item = (DexProtoId*) ptr;
617 CHECK_PTR_RANGE(item, item + 1);
618 SWAP_INDEX4(item->shortyIdx, state->pHeader->stringIdsSize);
619 SWAP_INDEX4(item->returnTypeIdx, state->pHeader->typeIdsSize);
620 SWAP_OFFSET4(item->parametersOff);
625 /* Helper for crossVerifyProtoIdItem(), which checks a shorty character
626 * to see if it is compatible with a type descriptor. Returns true if
627 * so, false if not. */
628 static bool shortyDescMatch(char shorty, const char* descriptor, bool
633 ALOGE("Invalid use of void");
646 if ((descriptor[0] != shorty) || (descriptor[1] != '\0')) {
647 ALOGE("Shorty vs. primitive type mismatch: '%c', '%s'",
654 if ((descriptor[0] != 'L') && (descriptor[0] != '[')) {
655 ALOGE("Shorty vs. type mismatch: '%c', '%s'",
662 ALOGE("Bogus shorty: '%c'", shorty);
670 /* Perform cross-item verification of proto_id_item. */
671 static void* crossVerifyProtoIdItem(const CheckState* state, void* ptr) {
672 const DexProtoId* item = (const DexProtoId*) ptr;
674 dexStringById(state->pDexFile, item->shortyIdx);
676 if (!dexDataMapVerify0Ok(state->pDataMap,
677 item->parametersOff, kDexTypeTypeList)) {
681 if (!shortyDescMatch(*shorty,
682 dexStringByTypeIdx(state->pDexFile, item->returnTypeIdx),
687 u4 protoIdx = item - state->pDexFile->pProtoIds;
688 DexProto proto = { state->pDexFile, protoIdx };
689 DexParameterIterator iterator;
691 dexParameterIteratorInit(&iterator, &proto);
692 shorty++; // Skip the return type.
695 const char *desc = dexParameterIteratorNextDescriptor(&iterator);
701 if (*shorty == '\0') {
702 ALOGE("Shorty is too short");
706 if (!shortyDescMatch(*shorty, desc, false)) {
713 if (*shorty != '\0') {
714 ALOGE("Shorty is too long");
718 const DexProtoId* item0 = (const DexProtoId*) state->previousItem;
720 // Check ordering. This relies on type_ids being in order.
721 if (item0->returnTypeIdx > item->returnTypeIdx) {
722 ALOGE("Out-of-order proto_id return types");
724 } else if (item0->returnTypeIdx == item->returnTypeIdx) {
725 bool badOrder = false;
726 DexProto proto0 = { state->pDexFile, protoIdx - 1 };
727 DexParameterIterator iterator0;
729 dexParameterIteratorInit(&iterator, &proto);
730 dexParameterIteratorInit(&iterator0, &proto0);
733 u4 idx0 = dexParameterIteratorNextIndex(&iterator0);
734 u4 idx1 = dexParameterIteratorNextIndex(&iterator);
736 if (idx1 == kDexNoIndex) {
741 if (idx0 == kDexNoIndex) {
747 } else if (idx0 > idx1) {
754 ALOGE("Out-of-order proto_id arguments");
760 return (void*) (item + 1);
763 /* Perform byte-swapping and intra-item verification on field_id_item. */
764 static void* swapFieldIdItem(const CheckState* state, void* ptr) {
765 DexFieldId* item = (DexFieldId*) ptr;
767 CHECK_PTR_RANGE(item, item + 1);
768 SWAP_INDEX2(item->classIdx, state->pHeader->typeIdsSize);
769 SWAP_INDEX2(item->typeIdx, state->pHeader->typeIdsSize);
770 SWAP_INDEX4(item->nameIdx, state->pHeader->stringIdsSize);
775 /* Perform cross-item verification of field_id_item. */
776 static void* crossVerifyFieldIdItem(const CheckState* state, void* ptr) {
777 const DexFieldId* item = (const DexFieldId*) ptr;
780 s = dexStringByTypeIdx(state->pDexFile, item->classIdx);
781 if (!dexIsClassDescriptor(s)) {
782 ALOGE("Invalid descriptor for class_idx: '%s'", s);
786 s = dexStringByTypeIdx(state->pDexFile, item->typeIdx);
787 if (!dexIsFieldDescriptor(s)) {
788 ALOGE("Invalid descriptor for type_idx: '%s'", s);
792 s = dexStringById(state->pDexFile, item->nameIdx);
793 if (!dexIsValidMemberName(s)) {
794 ALOGE("Invalid name: '%s'", s);
798 const DexFieldId* item0 = (const DexFieldId*) state->previousItem;
800 // Check ordering. This relies on the other sections being in order.
804 if (item0->classIdx > item->classIdx) {
807 } else if (item0->classIdx < item->classIdx) {
812 if (item0->nameIdx > item->nameIdx) {
815 } else if (item0->nameIdx < item->nameIdx) {
821 if (item0->typeIdx >= item->typeIdx) {
827 ALOGE("Out-of-order field_ids");
832 return (void*) (item + 1);
835 /* Perform byte-swapping and intra-item verification on method_id_item. */
836 static void* swapMethodIdItem(const CheckState* state, void* ptr) {
837 DexMethodId* item = (DexMethodId*) ptr;
839 CHECK_PTR_RANGE(item, item + 1);
840 SWAP_INDEX2(item->classIdx, state->pHeader->typeIdsSize);
841 SWAP_INDEX2(item->protoIdx, state->pHeader->protoIdsSize);
842 SWAP_INDEX4(item->nameIdx, state->pHeader->stringIdsSize);
847 /* Perform cross-item verification of method_id_item. */
848 static void* crossVerifyMethodIdItem(const CheckState* state, void* ptr) {
849 const DexMethodId* item = (const DexMethodId*) ptr;
852 s = dexStringByTypeIdx(state->pDexFile, item->classIdx);
853 if (!dexIsReferenceDescriptor(s)) {
854 ALOGE("Invalid descriptor for class_idx: '%s'", s);
858 s = dexStringById(state->pDexFile, item->nameIdx);
859 if (!dexIsValidMemberName(s)) {
860 ALOGE("Invalid name: '%s'", s);
864 const DexMethodId* item0 = (const DexMethodId*) state->previousItem;
866 // Check ordering. This relies on the other sections being in order.
870 if (item0->classIdx > item->classIdx) {
873 } else if (item0->classIdx < item->classIdx) {
878 if (item0->nameIdx > item->nameIdx) {
881 } else if (item0->nameIdx < item->nameIdx) {
887 if (item0->protoIdx >= item->protoIdx) {
893 ALOGE("Out-of-order method_ids");
898 return (void*) (item + 1);
901 /* Perform byte-swapping and intra-item verification on class_def_item. */
902 static void* swapClassDefItem(const CheckState* state, void* ptr) {
903 DexClassDef* item = (DexClassDef*) ptr;
905 CHECK_PTR_RANGE(item, item + 1);
906 SWAP_INDEX4(item->classIdx, state->pHeader->typeIdsSize);
907 SWAP_FIELD4(item->accessFlags);
908 SWAP_INDEX4_OR_NOINDEX(item->superclassIdx, state->pHeader->typeIdsSize);
909 SWAP_OFFSET4(item->interfacesOff);
910 SWAP_INDEX4_OR_NOINDEX(item->sourceFileIdx, state->pHeader->stringIdsSize);
911 SWAP_OFFSET4(item->annotationsOff);
912 SWAP_OFFSET4(item->classDataOff);
914 if ((item->accessFlags & ~ACC_CLASS_MASK) != 0) {
915 ALOGE("Bogus class access flags %x", item->accessFlags);
923 static u4 findFirstClassDataDefiner(const CheckState* state,
924 DexClassData* classData);
925 static u4 findFirstAnnotationsDirectoryDefiner(const CheckState* state,
926 const DexAnnotationsDirectoryItem* dir);
928 /* Helper for crossVerifyClassDefItem(), which checks a class_data_item to
929 * make sure all its references are to a given class. */
930 static bool verifyClassDataIsForDef(const CheckState* state, u4 offset,
936 const u1* data = (const u1*) filePointer(state, offset);
937 DexClassData* classData = dexReadAndVerifyClassData(&data, NULL);
939 if (classData == NULL) {
940 // Shouldn't happen, but bail here just in case.
945 * The class_data_item verification ensures that
946 * it consistently refers to the same definer, so all we need to
947 * do is check the first one.
949 u4 dataDefiner = findFirstClassDataDefiner(state, classData);
950 bool result = (dataDefiner == definerIdx) || (dataDefiner == kDexNoIndex);
956 /* Helper for crossVerifyClassDefItem(), which checks an
957 * annotations_directory_item to make sure all its references are to a
959 static bool verifyAnnotationsDirectoryIsForDef(const CheckState* state,
960 u4 offset, u4 definerIdx) {
965 const DexAnnotationsDirectoryItem* dir =
966 (const DexAnnotationsDirectoryItem*) filePointer(state, offset);
967 u4 annoDefiner = findFirstAnnotationsDirectoryDefiner(state, dir);
969 return (annoDefiner == definerIdx) || (annoDefiner == kDexNoIndex);
972 /* Perform cross-item verification of class_def_item. */
973 static void* crossVerifyClassDefItem(const CheckState* state, void* ptr) {
974 const DexClassDef* item = (const DexClassDef*) ptr;
975 u4 classIdx = item->classIdx;
976 const char* descriptor = dexStringByTypeIdx(state->pDexFile, classIdx);
978 if (!dexIsClassDescriptor(descriptor)) {
979 ALOGE("Invalid class: '%s'", descriptor);
983 if (setDefinedClassBit(state, classIdx)) {
984 ALOGE("Duplicate class definition: '%s'", descriptor);
989 dexDataMapVerify0Ok(state->pDataMap,
990 item->interfacesOff, kDexTypeTypeList)
991 && dexDataMapVerify0Ok(state->pDataMap,
992 item->annotationsOff, kDexTypeAnnotationsDirectoryItem)
993 && dexDataMapVerify0Ok(state->pDataMap,
994 item->classDataOff, kDexTypeClassDataItem)
995 && dexDataMapVerify0Ok(state->pDataMap,
996 item->staticValuesOff, kDexTypeEncodedArrayItem);
1002 if (item->superclassIdx != kDexNoIndex) {
1003 descriptor = dexStringByTypeIdx(state->pDexFile, item->superclassIdx);
1004 if (!dexIsClassDescriptor(descriptor)) {
1005 ALOGE("Invalid superclass: '%s'", descriptor);
1010 const DexTypeList* interfaces =
1011 dexGetInterfacesList(state->pDexFile, item);
1012 if (interfaces != NULL) {
1013 u4 size = interfaces->size;
1017 * Ensure that all interfaces refer to classes (not arrays or
1020 for (i = 0; i < size; i++) {
1021 descriptor = dexStringByTypeIdx(state->pDexFile,
1022 dexTypeListGetIdx(interfaces, i));
1023 if (!dexIsClassDescriptor(descriptor)) {
1024 ALOGE("Invalid interface: '%s'", descriptor);
1030 * Ensure that there are no duplicates. This is an O(N^2) test,
1031 * but in practice the number of interfaces implemented by any
1032 * given class is low. I will buy a milkshake for the
1033 * first person to show me a realistic case for which this test
1034 * would be unacceptably slow.
1036 for (i = 1; i < size; i++) {
1037 u4 idx1 = dexTypeListGetIdx(interfaces, i);
1039 for (j = 0; j < i; j++) {
1040 u4 idx2 = dexTypeListGetIdx(interfaces, j);
1042 ALOGE("Duplicate interface: '%s'",
1043 dexStringByTypeIdx(state->pDexFile, idx1));
1050 if (!verifyClassDataIsForDef(state, item->classDataOff, item->classIdx)) {
1051 ALOGE("Invalid class_data_item");
1055 if (!verifyAnnotationsDirectoryIsForDef(state, item->annotationsOff,
1057 ALOGE("Invalid annotations_directory_item");
1061 return (void*) (item + 1);
1064 /* Helper for swapAnnotationsDirectoryItem(), which performs
1065 * byte-swapping and intra-item verification on an
1066 * annotation_directory_item's field elements. */
1067 static u1* swapFieldAnnotations(const CheckState* state, u4 count, u1* addr) {
1068 DexFieldAnnotationsItem* item = (DexFieldAnnotationsItem*) addr;
1072 CHECK_LIST_SIZE(item, count, sizeof(DexFieldAnnotationsItem));
1075 SWAP_INDEX4(item->fieldIdx, state->pHeader->fieldIdsSize);
1076 SWAP_OFFSET4(item->annotationsOff);
1080 } else if (lastIdx >= item->fieldIdx) {
1081 ALOGE("Out-of-order field_idx: %#x then %#x", lastIdx,
1086 lastIdx = item->fieldIdx;
1093 /* Helper for swapAnnotationsDirectoryItem(), which performs
1094 * byte-swapping and intra-item verification on an
1095 * annotation_directory_item's method elements. */
1096 static u1* swapMethodAnnotations(const CheckState* state, u4 count, u1* addr) {
1097 DexMethodAnnotationsItem* item = (DexMethodAnnotationsItem*) addr;
1101 CHECK_LIST_SIZE(item, count, sizeof(DexMethodAnnotationsItem));
1104 SWAP_INDEX4(item->methodIdx, state->pHeader->methodIdsSize);
1105 SWAP_OFFSET4(item->annotationsOff);
1109 } else if (lastIdx >= item->methodIdx) {
1110 ALOGE("Out-of-order method_idx: %#x then %#x", lastIdx,
1115 lastIdx = item->methodIdx;
1122 /* Helper for swapAnnotationsDirectoryItem(), which performs
1123 * byte-swapping and intra-item verification on an
1124 * annotation_directory_item's parameter elements. */
1125 static u1* swapParameterAnnotations(const CheckState* state, u4 count,
1127 DexParameterAnnotationsItem* item = (DexParameterAnnotationsItem*) addr;
1131 CHECK_LIST_SIZE(item, count, sizeof(DexParameterAnnotationsItem));
1134 SWAP_INDEX4(item->methodIdx, state->pHeader->methodIdsSize);
1135 SWAP_OFFSET4(item->annotationsOff);
1139 } else if (lastIdx >= item->methodIdx) {
1140 ALOGE("Out-of-order method_idx: %#x then %#x", lastIdx,
1145 lastIdx = item->methodIdx;
1152 /* Perform byte-swapping and intra-item verification on
1153 * annotations_directory_item. */
1154 static void* swapAnnotationsDirectoryItem(const CheckState* state, void* ptr) {
1155 DexAnnotationsDirectoryItem* item = (DexAnnotationsDirectoryItem*) ptr;
1157 CHECK_PTR_RANGE(item, item + 1);
1158 SWAP_OFFSET4(item->classAnnotationsOff);
1159 SWAP_FIELD4(item->fieldsSize);
1160 SWAP_FIELD4(item->methodsSize);
1161 SWAP_FIELD4(item->parametersSize);
1163 u1* addr = (u1*) (item + 1);
1165 if (item->fieldsSize != 0) {
1166 addr = swapFieldAnnotations(state, item->fieldsSize, addr);
1172 if (item->methodsSize != 0) {
1173 addr = swapMethodAnnotations(state, item->methodsSize, addr);
1179 if (item->parametersSize != 0) {
1180 addr = swapParameterAnnotations(state, item->parametersSize, addr);
1189 /* Helper for crossVerifyAnnotationsDirectoryItem(), which checks the
1190 * field elements. */
1191 static const u1* crossVerifyFieldAnnotations(const CheckState* state, u4 count,
1192 const u1* addr, u4 definingClass) {
1193 const DexFieldAnnotationsItem* item = (DexFieldAnnotationsItem*) addr;
1196 if (!verifyFieldDefiner(state, definingClass, item->fieldIdx)) {
1199 if (!dexDataMapVerify(state->pDataMap, item->annotationsOff,
1200 kDexTypeAnnotationSetItem)) {
1206 return (const u1*) item;
1209 /* Helper for crossVerifyAnnotationsDirectoryItem(), which checks the
1210 * method elements. */
1211 static const u1* crossVerifyMethodAnnotations(const CheckState* state,
1212 u4 count, const u1* addr, u4 definingClass) {
1213 const DexMethodAnnotationsItem* item = (DexMethodAnnotationsItem*) addr;
1216 if (!verifyMethodDefiner(state, definingClass, item->methodIdx)) {
1219 if (!dexDataMapVerify(state->pDataMap, item->annotationsOff,
1220 kDexTypeAnnotationSetItem)) {
1226 return (const u1*) item;
1229 /* Helper for crossVerifyAnnotationsDirectoryItem(), which checks the
1230 * parameter elements. */
1231 static const u1* crossVerifyParameterAnnotations(const CheckState* state,
1232 u4 count, const u1* addr, u4 definingClass) {
1233 const DexParameterAnnotationsItem* item =
1234 (DexParameterAnnotationsItem*) addr;
1237 if (!verifyMethodDefiner(state, definingClass, item->methodIdx)) {
1240 if (!dexDataMapVerify(state->pDataMap, item->annotationsOff,
1241 kDexTypeAnnotationSetRefList)) {
1247 return (const u1*) item;
1250 /* Helper for crossVerifyClassDefItem() and
1251 * crossVerifyAnnotationsDirectoryItem(), which finds the type_idx of
1252 * the definer of the first item in the data. */
1253 static u4 findFirstAnnotationsDirectoryDefiner(const CheckState* state,
1254 const DexAnnotationsDirectoryItem* dir) {
1255 if (dir->fieldsSize != 0) {
1256 const DexFieldAnnotationsItem* fields =
1257 dexGetFieldAnnotations(state->pDexFile, dir);
1258 const DexFieldId* field =
1259 dexGetFieldId(state->pDexFile, fields[0].fieldIdx);
1260 return field->classIdx;
1263 if (dir->methodsSize != 0) {
1264 const DexMethodAnnotationsItem* methods =
1265 dexGetMethodAnnotations(state->pDexFile, dir);
1266 const DexMethodId* method =
1267 dexGetMethodId(state->pDexFile, methods[0].methodIdx);
1268 return method->classIdx;
1271 if (dir->parametersSize != 0) {
1272 const DexParameterAnnotationsItem* parameters =
1273 dexGetParameterAnnotations(state->pDexFile, dir);
1274 const DexMethodId* method =
1275 dexGetMethodId(state->pDexFile, parameters[0].methodIdx);
1276 return method->classIdx;
1282 /* Perform cross-item verification of annotations_directory_item. */
1283 static void* crossVerifyAnnotationsDirectoryItem(const CheckState* state,
1285 const DexAnnotationsDirectoryItem* item = (const DexAnnotationsDirectoryItem*) ptr;
1286 u4 definingClass = findFirstAnnotationsDirectoryDefiner(state, item);
1288 if (!dexDataMapVerify0Ok(state->pDataMap,
1289 item->classAnnotationsOff, kDexTypeAnnotationSetItem)) {
1293 const u1* addr = (const u1*) (item + 1);
1295 if (item->fieldsSize != 0) {
1296 addr = crossVerifyFieldAnnotations(state, item->fieldsSize, addr,
1303 if (item->methodsSize != 0) {
1304 addr = crossVerifyMethodAnnotations(state, item->methodsSize, addr,
1311 if (item->parametersSize != 0) {
1312 addr = crossVerifyParameterAnnotations(state, item->parametersSize,
1313 addr, definingClass);
1319 return (void*) addr;
1322 /* Perform byte-swapping and intra-item verification on type_list. */
1323 static void* swapTypeList(const CheckState* state, void* ptr)
1325 DexTypeList* pTypeList = (DexTypeList*) ptr;
1329 CHECK_PTR_RANGE(pTypeList, pTypeList + 1);
1330 SWAP_FIELD4(pTypeList->size);
1331 count = pTypeList->size;
1332 pType = pTypeList->list;
1333 CHECK_LIST_SIZE(pType, count, sizeof(DexTypeItem));
1336 SWAP_INDEX2(pType->typeIdx, state->pHeader->typeIdsSize);
1343 /* Perform byte-swapping and intra-item verification on
1344 * annotation_set_ref_list. */
1345 static void* swapAnnotationSetRefList(const CheckState* state, void* ptr) {
1346 DexAnnotationSetRefList* list = (DexAnnotationSetRefList*) ptr;
1347 DexAnnotationSetRefItem* item;
1350 CHECK_PTR_RANGE(list, list + 1);
1351 SWAP_FIELD4(list->size);
1354 CHECK_LIST_SIZE(item, count, sizeof(DexAnnotationSetRefItem));
1357 SWAP_OFFSET4(item->annotationsOff);
1364 /* Perform cross-item verification of annotation_set_ref_list. */
1365 static void* crossVerifyAnnotationSetRefList(const CheckState* state,
1367 const DexAnnotationSetRefList* list = (const DexAnnotationSetRefList*) ptr;
1368 const DexAnnotationSetRefItem* item = list->list;
1369 int count = list->size;
1372 if (!dexDataMapVerify0Ok(state->pDataMap,
1373 item->annotationsOff, kDexTypeAnnotationSetItem)) {
1379 return (void*) item;
1382 /* Perform byte-swapping and intra-item verification on
1383 * annotation_set_item. */
1384 static void* swapAnnotationSetItem(const CheckState* state, void* ptr) {
1385 DexAnnotationSetItem* set = (DexAnnotationSetItem*) ptr;
1389 CHECK_PTR_RANGE(set, set + 1);
1390 SWAP_FIELD4(set->size);
1392 item = set->entries;
1393 CHECK_LIST_SIZE(item, count, sizeof(u4));
1396 SWAP_OFFSET4(*item);
1403 /* Helper for crossVerifyAnnotationSetItem(), which extracts the type_idx
1404 * out of an annotation_item. */
1405 static u4 annotationItemTypeIdx(const DexAnnotationItem* item) {
1406 const u1* data = item->annotation;
1407 return readUnsignedLeb128(&data);
1410 /* Perform cross-item verification of annotation_set_item. */
1411 static void* crossVerifyAnnotationSetItem(const CheckState* state, void* ptr) {
1412 const DexAnnotationSetItem* set = (const DexAnnotationSetItem*) ptr;
1413 int count = set->size;
1418 for (i = 0; i < count; i++) {
1419 if (!dexDataMapVerify0Ok(state->pDataMap,
1420 dexGetAnnotationOff(set, i), kDexTypeAnnotationItem)) {
1424 const DexAnnotationItem* annotation =
1425 dexGetAnnotationItem(state->pDexFile, set, i);
1426 u4 idx = annotationItemTypeIdx(annotation);
1430 } else if (lastIdx >= idx) {
1431 ALOGE("Out-of-order entry types: %#x then %#x",
1439 return (void*) (set->entries + count);
1442 /* Helper for verifyClassDataItem(), which checks a list of fields. */
1443 static bool verifyFields(const CheckState* state, u4 size,
1444 DexField* fields, bool expectStatic) {
1447 for (i = 0; i < size; i++) {
1448 DexField* field = &fields[i];
1449 u4 accessFlags = field->accessFlags;
1450 bool isStatic = (accessFlags & ACC_STATIC) != 0;
1452 CHECK_INDEX(field->fieldIdx, state->pHeader->fieldIdsSize);
1454 if (isStatic != expectStatic) {
1455 ALOGE("Field in wrong list @ %d", i);
1459 if ((accessFlags & ~ACC_FIELD_MASK) != 0) {
1460 ALOGE("Bogus field access flags %x @ %d", accessFlags, i);
1468 /* Helper for verifyClassDataItem(), which checks a list of methods. */
1469 static bool verifyMethods(const CheckState* state, u4 size,
1470 DexMethod* methods, bool expectDirect) {
1473 for (i = 0; i < size; i++) {
1474 DexMethod* method = &methods[i];
1476 CHECK_INDEX(method->methodIdx, state->pHeader->methodIdsSize);
1478 u4 accessFlags = method->accessFlags;
1480 (accessFlags & (ACC_STATIC | ACC_PRIVATE | ACC_CONSTRUCTOR)) != 0;
1481 bool expectCode = (accessFlags & (ACC_NATIVE | ACC_ABSTRACT)) == 0;
1482 bool isSynchronized = (accessFlags & ACC_SYNCHRONIZED) != 0;
1483 bool allowSynchronized = (accessFlags & ACC_NATIVE) != 0;
1485 if (isDirect != expectDirect) {
1486 ALOGE("Method in wrong list @ %d", i);
1490 if (((accessFlags & ~ACC_METHOD_MASK) != 0)
1491 || (isSynchronized && !allowSynchronized)) {
1492 ALOGE("Bogus method access flags %x @ %d", accessFlags, i);
1497 if (method->codeOff == 0) {
1498 ALOGE("Unexpected zero code_off for access_flags %x",
1502 } else if (method->codeOff != 0) {
1503 ALOGE("Unexpected non-zero code_off %#x for access_flags %x",
1504 method->codeOff, accessFlags);
1512 /* Helper for verifyClassDataItem(), which does most of the work. */
1513 static bool verifyClassDataItem0(const CheckState* state,
1514 DexClassData* classData) {
1517 okay = verifyFields(state, classData->header.staticFieldsSize,
1518 classData->staticFields, true);
1521 ALOGE("Trouble with static fields");
1525 verifyFields(state, classData->header.instanceFieldsSize,
1526 classData->instanceFields, false);
1529 ALOGE("Trouble with instance fields");
1533 okay = verifyMethods(state, classData->header.directMethodsSize,
1534 classData->directMethods, true);
1537 ALOGE("Trouble with direct methods");
1541 okay = verifyMethods(state, classData->header.virtualMethodsSize,
1542 classData->virtualMethods, false);
1545 ALOGE("Trouble with virtual methods");
1552 /* Perform intra-item verification on class_data_item. */
1553 static void* intraVerifyClassDataItem(const CheckState* state, void* ptr) {
1554 const u1* data = (const u1*) ptr;
1555 DexClassData* classData = dexReadAndVerifyClassData(&data, state->fileEnd);
1557 if (classData == NULL) {
1558 ALOGE("Unable to parse class_data_item");
1562 bool okay = verifyClassDataItem0(state, classData);
1570 return (void*) data;
1573 /* Helper for crossVerifyClassDefItem() and
1574 * crossVerifyClassDataItem(), which finds the type_idx of the definer
1575 * of the first item in the data. */
1576 static u4 findFirstClassDataDefiner(const CheckState* state,
1577 DexClassData* classData) {
1578 if (classData->header.staticFieldsSize != 0) {
1579 u4 fieldIdx = classData->staticFields[0].fieldIdx;
1580 const DexFieldId* field = dexGetFieldId(state->pDexFile, fieldIdx);
1581 return field->classIdx;
1584 if (classData->header.instanceFieldsSize != 0) {
1585 u4 fieldIdx = classData->instanceFields[0].fieldIdx;
1586 const DexFieldId* field = dexGetFieldId(state->pDexFile, fieldIdx);
1587 return field->classIdx;
1590 if (classData->header.directMethodsSize != 0) {
1591 u4 methodIdx = classData->directMethods[0].methodIdx;
1592 const DexMethodId* meth = dexGetMethodId(state->pDexFile, methodIdx);
1593 return meth->classIdx;
1596 if (classData->header.virtualMethodsSize != 0) {
1597 u4 methodIdx = classData->virtualMethods[0].methodIdx;
1598 const DexMethodId* meth = dexGetMethodId(state->pDexFile, methodIdx);
1599 return meth->classIdx;
1605 /* Perform cross-item verification of class_data_item. */
1606 static void* crossVerifyClassDataItem(const CheckState* state, void* ptr) {
1607 const u1* data = (const u1*) ptr;
1608 DexClassData* classData = dexReadAndVerifyClassData(&data, state->fileEnd);
1609 u4 definingClass = findFirstClassDataDefiner(state, classData);
1613 for (i = classData->header.staticFieldsSize; okay && (i > 0); /*i*/) {
1615 const DexField* field = &classData->staticFields[i];
1616 okay = verifyFieldDefiner(state, definingClass, field->fieldIdx);
1619 for (i = classData->header.instanceFieldsSize; okay && (i > 0); /*i*/) {
1621 const DexField* field = &classData->instanceFields[i];
1622 okay = verifyFieldDefiner(state, definingClass, field->fieldIdx);
1625 for (i = classData->header.directMethodsSize; okay && (i > 0); /*i*/) {
1627 const DexMethod* meth = &classData->directMethods[i];
1628 okay = dexDataMapVerify0Ok(state->pDataMap, meth->codeOff,
1630 && verifyMethodDefiner(state, definingClass, meth->methodIdx);
1633 for (i = classData->header.virtualMethodsSize; okay && (i > 0); /*i*/) {
1635 const DexMethod* meth = &classData->virtualMethods[i];
1636 okay = dexDataMapVerify0Ok(state->pDataMap, meth->codeOff,
1638 && verifyMethodDefiner(state, definingClass, meth->methodIdx);
1647 return (void*) data;
1650 /* Helper for swapCodeItem(), which fills an array with all the valid
1651 * handlerOff values for catch handlers and also verifies the handler
1653 static u4 setHandlerOffsAndVerify(const CheckState* state,
1654 DexCode* code, u4 firstOffset, u4 handlersSize, u4* handlerOffs) {
1655 const u1* fileEnd = state->fileEnd;
1656 const u1* handlersBase = dexGetCatchHandlerData(code);
1657 u4 offset = firstOffset;
1661 for (i = 0; i < handlersSize; i++) {
1662 const u1* ptr = handlersBase + offset;
1663 int size = readAndVerifySignedLeb128(&ptr, fileEnd, &okay);
1667 ALOGE("Bogus size");
1671 if ((size < -65536) || (size > 65536)) {
1672 ALOGE("Invalid size: %d", size);
1683 handlerOffs[i] = offset;
1685 while (size-- > 0) {
1687 readAndVerifyUnsignedLeb128(&ptr, fileEnd, &okay);
1690 ALOGE("Bogus type_idx");
1694 CHECK_INDEX(typeIdx, state->pHeader->typeIdsSize);
1696 u4 addr = readAndVerifyUnsignedLeb128(&ptr, fileEnd, &okay);
1699 ALOGE("Bogus addr");
1703 if (addr >= code->insnsSize) {
1704 ALOGE("Invalid addr: %#x", addr);
1710 u4 addr = readAndVerifyUnsignedLeb128(&ptr, fileEnd, &okay);
1713 ALOGE("Bogus catch_all_addr");
1717 if (addr >= code->insnsSize) {
1718 ALOGE("Invalid catch_all_addr: %#x", addr);
1723 offset = ptr - handlersBase;
1729 /* Helper for swapCodeItem(), which does all the try-catch related
1730 * swapping and verification. */
1731 static void* swapTriesAndCatches(const CheckState* state, DexCode* code) {
1732 const u1* encodedHandlers = dexGetCatchHandlerData(code);
1733 const u1* encodedPtr = encodedHandlers;
1736 readAndVerifyUnsignedLeb128(&encodedPtr, state->fileEnd, &okay);
1739 ALOGE("Bogus handlers_size");
1743 if ((handlersSize == 0) || (handlersSize >= 65536)) {
1744 ALOGE("Invalid handlers_size: %d", handlersSize);
1748 u4 handlerOffs[handlersSize]; // list of valid handlerOff values
1749 u4 endOffset = setHandlerOffsAndVerify(state, code,
1750 encodedPtr - encodedHandlers,
1751 handlersSize, handlerOffs);
1753 if (endOffset == 0) {
1757 DexTry* tries = (DexTry*) dexGetTries(code);
1758 u4 count = code->triesSize;
1761 CHECK_LIST_SIZE(tries, count, sizeof(DexTry));
1766 SWAP_FIELD4(tries->startAddr);
1767 SWAP_FIELD2(tries->insnCount);
1768 SWAP_FIELD2(tries->handlerOff);
1770 if (tries->startAddr < lastEnd) {
1771 ALOGE("Out-of-order try");
1775 if (tries->startAddr >= code->insnsSize) {
1776 ALOGE("Invalid start_addr: %#x", tries->startAddr);
1780 for (i = 0; i < handlersSize; i++) {
1781 if (tries->handlerOff == handlerOffs[i]) {
1786 if (i == handlersSize) {
1787 ALOGE("Bogus handler offset: %#x", tries->handlerOff);
1791 lastEnd = tries->startAddr + tries->insnCount;
1793 if (lastEnd > code->insnsSize) {
1794 ALOGE("Invalid insn_count: %#x (end addr %#x)",
1795 tries->insnCount, lastEnd);
1802 return (u1*) encodedHandlers + endOffset;
1805 /* Perform byte-swapping and intra-item verification on code_item. */
1806 static void* swapCodeItem(const CheckState* state, void* ptr) {
1807 DexCode* item = (DexCode*) ptr;
1811 CHECK_PTR_RANGE(item, item + 1);
1812 SWAP_FIELD2(item->registersSize);
1813 SWAP_FIELD2(item->insSize);
1814 SWAP_FIELD2(item->outsSize);
1815 SWAP_FIELD2(item->triesSize);
1816 SWAP_OFFSET4(item->debugInfoOff);
1817 SWAP_FIELD4(item->insnsSize);
1819 if (item->insSize > item->registersSize) {
1820 ALOGE("insSize (%u) > registersSize (%u)", item->insSize,
1821 item->registersSize);
1825 if ((item->outsSize > 5) && (item->outsSize > item->registersSize)) {
1827 * It's okay for outsSize to be up to five, even if registersSize
1828 * is smaller, since the short forms of method invocation allow
1829 * repetition of a register multiple times within a single parameter
1830 * list. Longer parameter lists, though, need to be represented
1831 * in-order in the register file.
1833 ALOGE("outsSize (%u) > registersSize (%u)", item->outsSize,
1834 item->registersSize);
1838 count = item->insnsSize;
1839 insns = item->insns;
1840 CHECK_LIST_SIZE(insns, count, sizeof(u2));
1843 *insns = SWAP2(*insns);
1847 if (item->triesSize == 0) {
1850 if ((((uintptr_t) insns) & 3) != 0) {
1851 // Four-byte alignment for the tries. Verify the spacer is a 0.
1853 ALOGE("Non-zero padding: %#x", (u4) *insns);
1858 ptr = swapTriesAndCatches(state, item);
1864 /* Perform intra-item verification on string_data_item. */
1865 static void* intraVerifyStringDataItem(const CheckState* state, void* ptr) {
1866 const u1* fileEnd = state->fileEnd;
1867 const u1* data = (const u1*) ptr;
1869 u4 utf16Size = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
1873 ALOGE("Bogus utf16_size");
1877 for (i = 0; i < utf16Size; i++) {
1878 if (data >= fileEnd) {
1879 ALOGE("String data would go beyond end-of-file");
1883 u1 byte1 = *(data++);
1885 // Switch on the high four bits.
1886 switch (byte1 >> 4) {
1888 // Special case of bit pattern 0xxx.
1890 ALOGE("String shorter than indicated utf16_size %#x",
1903 // Bit pattern 0xxx. No need for any extra bytes or checks.
1912 * Bit pattern 10xx or 1111, which are illegal start bytes.
1913 * Note: 1111 is valid for normal UTF-8, but not the
1914 * modified UTF-8 used here.
1916 ALOGE("Illegal start byte %#x", byte1);
1920 // Bit pattern 1110, so there are two additional bytes.
1921 u1 byte2 = *(data++);
1922 if ((byte2 & 0xc0) != 0x80) {
1923 ALOGE("Illegal continuation byte %#x", byte2);
1926 u1 byte3 = *(data++);
1927 if ((byte3 & 0xc0) != 0x80) {
1928 ALOGE("Illegal continuation byte %#x", byte3);
1931 u2 value = ((byte1 & 0x0f) << 12) | ((byte2 & 0x3f) << 6)
1933 if (value < 0x800) {
1934 ALOGE("Illegal representation for value %x", value);
1941 // Bit pattern 110x, so there is one additional byte.
1942 u1 byte2 = *(data++);
1943 if ((byte2 & 0xc0) != 0x80) {
1944 ALOGE("Illegal continuation byte %#x", byte2);
1947 u2 value = ((byte1 & 0x1f) << 6) | (byte2 & 0x3f);
1948 if ((value != 0) && (value < 0x80)) {
1949 ALOGE("Illegal representation for value %x", value);
1957 if (*(data++) != '\0') {
1958 ALOGE("String longer than indicated utf16_size %#x", utf16Size);
1962 return (void*) data;
1965 /* Perform intra-item verification on debug_info_item. */
1966 static void* intraVerifyDebugInfoItem(const CheckState* state, void* ptr) {
1967 const u1* fileEnd = state->fileEnd;
1968 const u1* data = (const u1*) ptr;
1972 readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
1975 ALOGE("Bogus line_start");
1980 readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
1983 ALOGE("Bogus parameters_size");
1987 if (parametersSize > 65536) {
1988 ALOGE("Invalid parameters_size: %#x", parametersSize);
1992 for (i = 0; i < parametersSize; i++) {
1994 readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
1997 ALOGE("Bogus parameter_name");
2001 if (parameterName != 0) {
2003 CHECK_INDEX(parameterName, state->pHeader->stringIdsSize);
2009 u1 opcode = *(data++);
2012 case DBG_END_SEQUENCE: {
2016 case DBG_ADVANCE_PC: {
2017 readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2020 case DBG_ADVANCE_LINE: {
2021 readAndVerifySignedLeb128(&data, fileEnd, &okay);
2024 case DBG_START_LOCAL: {
2026 u4 regNum = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2028 if (regNum >= 65536) {
2032 idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2036 CHECK_INDEX(idx, state->pHeader->stringIdsSize);
2038 idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2042 CHECK_INDEX(idx, state->pHeader->stringIdsSize);
2047 case DBG_RESTART_LOCAL: {
2048 u4 regNum = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2050 if (regNum >= 65536) {
2056 case DBG_START_LOCAL_EXTENDED: {
2058 u4 regNum = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2060 if (regNum >= 65536) {
2064 idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2068 CHECK_INDEX(idx, state->pHeader->stringIdsSize);
2070 idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2074 CHECK_INDEX(idx, state->pHeader->stringIdsSize);
2076 idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2080 CHECK_INDEX(idx, state->pHeader->stringIdsSize);
2084 case DBG_SET_FILE: {
2085 u4 idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2089 CHECK_INDEX(idx, state->pHeader->stringIdsSize);
2094 // No arguments to parse for anything else.
2099 ALOGE("Bogus syntax for opcode %02x", opcode);
2104 return (void*) data;
2108 static const u1* verifyEncodedValue(const CheckState* state, const u1* data,
2110 static const u1* verifyEncodedAnnotation(const CheckState* state,
2111 const u1* data, bool crossVerify);
2113 /* Helper for verifyEncodedValue(), which reads a 1- to 4- byte unsigned
2114 * little endian value. */
2115 static u4 readUnsignedLittleEndian(const CheckState* state, const u1** pData,
2117 const u1* data = *pData;
2121 CHECK_PTR_RANGE(data, data + size);
2123 for (i = 0; i < size; i++) {
2124 result |= ((u4) *(data++)) << (i * 8);
2131 /* Helper for *VerifyAnnotationItem() and *VerifyEncodedArrayItem(), which
2132 * verifies an encoded_array. */
2133 static const u1* verifyEncodedArray(const CheckState* state,
2134 const u1* data, bool crossVerify) {
2136 u4 size = readAndVerifyUnsignedLeb128(&data, state->fileEnd, &okay);
2139 ALOGE("Bogus encoded_array size");
2144 data = verifyEncodedValue(state, data, crossVerify);
2146 ALOGE("Bogus encoded_array value");
2154 /* Helper for *VerifyAnnotationItem() and *VerifyEncodedArrayItem(), which
2155 * verifies an encoded_value. */
2156 static const u1* verifyEncodedValue(const CheckState* state,
2157 const u1* data, bool crossVerify) {
2158 CHECK_PTR_RANGE(data, data + 1);
2160 u1 headerByte = *(data++);
2161 u4 valueType = headerByte & kDexAnnotationValueTypeMask;
2162 u4 valueArg = headerByte >> kDexAnnotationValueArgShift;
2164 switch (valueType) {
2165 case kDexAnnotationByte: {
2166 if (valueArg != 0) {
2167 ALOGE("Bogus byte size %#x", valueArg);
2173 case kDexAnnotationShort:
2174 case kDexAnnotationChar: {
2176 ALOGE("Bogus char/short size %#x", valueArg);
2179 data += valueArg + 1;
2182 case kDexAnnotationInt:
2183 case kDexAnnotationFloat: {
2185 ALOGE("Bogus int/float size %#x", valueArg);
2188 data += valueArg + 1;
2191 case kDexAnnotationLong:
2192 case kDexAnnotationDouble: {
2193 data += valueArg + 1;
2196 case kDexAnnotationString: {
2198 ALOGE("Bogus string size %#x", valueArg);
2201 u4 idx = readUnsignedLittleEndian(state, &data, valueArg + 1);
2202 CHECK_INDEX(idx, state->pHeader->stringIdsSize);
2205 case kDexAnnotationType: {
2207 ALOGE("Bogus type size %#x", valueArg);
2210 u4 idx = readUnsignedLittleEndian(state, &data, valueArg + 1);
2211 CHECK_INDEX(idx, state->pHeader->typeIdsSize);
2214 case kDexAnnotationField:
2215 case kDexAnnotationEnum: {
2217 ALOGE("Bogus field/enum size %#x", valueArg);
2220 u4 idx = readUnsignedLittleEndian(state, &data, valueArg + 1);
2221 CHECK_INDEX(idx, state->pHeader->fieldIdsSize);
2224 case kDexAnnotationMethod: {
2226 ALOGE("Bogus method size %#x", valueArg);
2229 u4 idx = readUnsignedLittleEndian(state, &data, valueArg + 1);
2230 CHECK_INDEX(idx, state->pHeader->methodIdsSize);
2233 case kDexAnnotationArray: {
2234 if (valueArg != 0) {
2235 ALOGE("Bogus array value_arg %#x", valueArg);
2238 data = verifyEncodedArray(state, data, crossVerify);
2241 case kDexAnnotationAnnotation: {
2242 if (valueArg != 0) {
2243 ALOGE("Bogus annotation value_arg %#x", valueArg);
2246 data = verifyEncodedAnnotation(state, data, crossVerify);
2249 case kDexAnnotationNull: {
2250 if (valueArg != 0) {
2251 ALOGE("Bogus null value_arg %#x", valueArg);
2254 // Nothing else to do for this type.
2257 case kDexAnnotationBoolean: {
2259 ALOGE("Bogus boolean value_arg %#x", valueArg);
2262 // Nothing else to do for this type.
2266 ALOGE("Bogus value_type %#x", valueType);
2274 /* Helper for *VerifyAnnotationItem() and *VerifyEncodedArrayItem(), which
2275 * verifies an encoded_annotation. */
2276 static const u1* verifyEncodedAnnotation(const CheckState* state,
2277 const u1* data, bool crossVerify) {
2278 const u1* fileEnd = state->fileEnd;
2280 u4 idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2283 ALOGE("Bogus encoded_annotation type_idx");
2287 CHECK_INDEX(idx, state->pHeader->typeIdsSize);
2290 const char* descriptor = dexStringByTypeIdx(state->pDexFile, idx);
2291 if (!dexIsClassDescriptor(descriptor)) {
2292 ALOGE("Bogus annotation type: '%s'", descriptor);
2297 u4 size = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2302 ALOGE("Bogus encoded_annotation size");
2307 idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2310 ALOGE("Bogus encoded_annotation name_idx");
2314 CHECK_INDEX(idx, state->pHeader->stringIdsSize);
2317 const char* name = dexStringById(state->pDexFile, idx);
2318 if (!dexIsValidMemberName(name)) {
2319 ALOGE("Bogus annotation member name: '%s'", name);
2326 } else if (lastIdx >= idx) {
2327 ALOGE("Out-of-order encoded_annotation name_idx: %#x then %#x",
2332 data = verifyEncodedValue(state, data, crossVerify);
2343 /* Perform intra-item verification on encoded_array_item. */
2344 static void* intraVerifyEncodedArrayItem(const CheckState* state, void* ptr) {
2345 return (void*) verifyEncodedArray(state, (const u1*) ptr, false);
2348 /* Perform intra-item verification on annotation_item. */
2349 static void* intraVerifyAnnotationItem(const CheckState* state, void* ptr) {
2350 const u1* data = (const u1*) ptr;
2352 CHECK_PTR_RANGE(data, data + 1);
2354 switch (*(data++)) {
2355 case kDexVisibilityBuild:
2356 case kDexVisibilityRuntime:
2357 case kDexVisibilitySystem: {
2361 ALOGE("Bogus annotation visibility: %#x", *data);
2366 return (void*) verifyEncodedAnnotation(state, data, false);
2369 /* Perform cross-item verification on annotation_item. */
2370 static void* crossVerifyAnnotationItem(const CheckState* state, void* ptr) {
2371 const u1* data = (const u1*) ptr;
2373 // Skip the visibility byte.
2376 return (void*) verifyEncodedAnnotation(state, data, true);
2383 * Function to visit an individual top-level item type.
2385 typedef void* ItemVisitorFunction(const CheckState* state, void* ptr);
2388 * Iterate over all the items in a section, optionally updating the
2389 * data map (done if mapType is passed as non-negative). The section
2390 * must consist of concatenated items of the same type.
2392 static bool iterateSectionWithOptionalUpdate(CheckState* state,
2393 u4 offset, u4 count, ItemVisitorFunction* func, u4 alignment,
2394 u4* nextOffset, int mapType) {
2395 u4 alignmentMask = alignment - 1;
2398 state->previousItem = NULL;
2400 for (i = 0; i < count; i++) {
2401 u4 newOffset = (offset + alignmentMask) & ~alignmentMask;
2402 u1* ptr = (u1*) filePointer(state, newOffset);
2404 if (offset < newOffset) {
2405 ptr = (u1*) filePointer(state, offset);
2406 if (offset < newOffset) {
2407 CHECK_OFFSET_RANGE(offset, newOffset);
2408 while (offset < newOffset) {
2410 ALOGE("Non-zero padding 0x%02x @ %x", *ptr, offset);
2419 u1* newPtr = (u1*) func(state, ptr);
2420 newOffset = fileOffset(state, newPtr);
2422 if (newPtr == NULL) {
2423 ALOGE("Trouble with item %d @ offset %#x", i, offset);
2427 if (newOffset > state->fileLen) {
2428 ALOGE("Item %d @ offset %#x ends out of bounds", i, offset);
2433 dexDataMapAdd(state->pDataMap, offset, mapType);
2436 state->previousItem = ptr;
2440 if (nextOffset != NULL) {
2441 *nextOffset = offset;
2448 * Iterate over all the items in a section. The section must consist of
2449 * concatenated items of the same type. This variant will not update the data
2452 static bool iterateSection(CheckState* state, u4 offset, u4 count,
2453 ItemVisitorFunction* func, u4 alignment, u4* nextOffset) {
2454 return iterateSectionWithOptionalUpdate(state, offset, count, func,
2455 alignment, nextOffset, -1);
2459 * Like iterateSection(), but also check that the offset and count match
2460 * a given pair of expected values.
2462 static bool checkBoundsAndIterateSection(CheckState* state,
2463 u4 offset, u4 count, u4 expectedOffset, u4 expectedCount,
2464 ItemVisitorFunction* func, u4 alignment, u4* nextOffset) {
2465 if (offset != expectedOffset) {
2466 ALOGE("Bogus offset for section: got %#x; expected %#x",
2467 offset, expectedOffset);
2471 if (count != expectedCount) {
2472 ALOGE("Bogus size for section: got %#x; expected %#x",
2473 count, expectedCount);
2477 return iterateSection(state, offset, count, func, alignment, nextOffset);
2481 * Like iterateSection(), but also update the data section map and
2482 * check that all the items fall within the data section.
2484 static bool iterateDataSection(CheckState* state, u4 offset, u4 count,
2485 ItemVisitorFunction* func, u4 alignment, u4* nextOffset, int mapType) {
2486 u4 dataStart = state->pHeader->dataOff;
2487 u4 dataEnd = dataStart + state->pHeader->dataSize;
2489 assert(nextOffset != NULL);
2491 if ((offset < dataStart) || (offset >= dataEnd)) {
2492 ALOGE("Bogus offset for data subsection: %#x", offset);
2496 if (!iterateSectionWithOptionalUpdate(state, offset, count, func,
2497 alignment, nextOffset, mapType)) {
2501 if (*nextOffset > dataEnd) {
2502 ALOGE("Out-of-bounds end of data subsection: %#x", *nextOffset);
2510 * Byte-swap all items in the given map except the header and the map
2511 * itself, both of which should have already gotten swapped. This also
2512 * does all possible intra-item verification, that is, verification
2513 * that doesn't need to assume the sanctity of the contents of *other*
2514 * items. The intra-item limitation is because at the time an item is
2515 * asked to verify itself, it can't assume that the items it refers to
2516 * have been byte-swapped and verified.
2518 static bool swapEverythingButHeaderAndMap(CheckState* state,
2520 const DexMapItem* item = pMap->list;
2522 u4 count = pMap->size;
2525 while (okay && count--) {
2526 u4 sectionOffset = item->offset;
2527 u4 sectionCount = item->size;
2528 u2 type = item->type;
2530 if (lastOffset < sectionOffset) {
2531 CHECK_OFFSET_RANGE(lastOffset, sectionOffset);
2532 const u1* ptr = (const u1*) filePointer(state, lastOffset);
2533 while (lastOffset < sectionOffset) {
2535 ALOGE("Non-zero padding 0x%02x before section start @ %x",
2543 } else if (lastOffset > sectionOffset) {
2544 ALOGE("Section overlap or out-of-order map: %x, %x",
2545 lastOffset, sectionOffset);
2554 case kDexTypeHeaderItem: {
2556 * The header got swapped very early on, but do some
2557 * additional sanity checking here.
2559 okay = checkHeaderSection(state, sectionOffset, sectionCount,
2563 case kDexTypeStringIdItem: {
2564 okay = checkBoundsAndIterateSection(state, sectionOffset,
2565 sectionCount, state->pHeader->stringIdsOff,
2566 state->pHeader->stringIdsSize, swapStringIdItem,
2567 sizeof(u4), &lastOffset);
2570 case kDexTypeTypeIdItem: {
2571 okay = checkBoundsAndIterateSection(state, sectionOffset,
2572 sectionCount, state->pHeader->typeIdsOff,
2573 state->pHeader->typeIdsSize, swapTypeIdItem,
2574 sizeof(u4), &lastOffset);
2577 case kDexTypeProtoIdItem: {
2578 okay = checkBoundsAndIterateSection(state, sectionOffset,
2579 sectionCount, state->pHeader->protoIdsOff,
2580 state->pHeader->protoIdsSize, swapProtoIdItem,
2581 sizeof(u4), &lastOffset);
2584 case kDexTypeFieldIdItem: {
2585 okay = checkBoundsAndIterateSection(state, sectionOffset,
2586 sectionCount, state->pHeader->fieldIdsOff,
2587 state->pHeader->fieldIdsSize, swapFieldIdItem,
2588 sizeof(u4), &lastOffset);
2591 case kDexTypeMethodIdItem: {
2592 okay = checkBoundsAndIterateSection(state, sectionOffset,
2593 sectionCount, state->pHeader->methodIdsOff,
2594 state->pHeader->methodIdsSize, swapMethodIdItem,
2595 sizeof(u4), &lastOffset);
2598 case kDexTypeClassDefItem: {
2599 okay = checkBoundsAndIterateSection(state, sectionOffset,
2600 sectionCount, state->pHeader->classDefsOff,
2601 state->pHeader->classDefsSize, swapClassDefItem,
2602 sizeof(u4), &lastOffset);
2605 case kDexTypeMapList: {
2607 * The map section was swapped early on, but do some
2608 * additional sanity checking here.
2610 okay = checkMapSection(state, sectionOffset, sectionCount,
2614 case kDexTypeTypeList: {
2615 okay = iterateDataSection(state, sectionOffset, sectionCount,
2616 swapTypeList, sizeof(u4), &lastOffset, type);
2619 case kDexTypeAnnotationSetRefList: {
2620 okay = iterateDataSection(state, sectionOffset, sectionCount,
2621 swapAnnotationSetRefList, sizeof(u4), &lastOffset,
2625 case kDexTypeAnnotationSetItem: {
2626 okay = iterateDataSection(state, sectionOffset, sectionCount,
2627 swapAnnotationSetItem, sizeof(u4), &lastOffset, type);
2630 case kDexTypeClassDataItem: {
2631 okay = iterateDataSection(state, sectionOffset, sectionCount,
2632 intraVerifyClassDataItem, sizeof(u1), &lastOffset,
2636 case kDexTypeCodeItem: {
2637 okay = iterateDataSection(state, sectionOffset, sectionCount,
2638 swapCodeItem, sizeof(u4), &lastOffset, type);
2641 case kDexTypeStringDataItem: {
2642 okay = iterateDataSection(state, sectionOffset, sectionCount,
2643 intraVerifyStringDataItem, sizeof(u1), &lastOffset,
2647 case kDexTypeDebugInfoItem: {
2648 okay = iterateDataSection(state, sectionOffset, sectionCount,
2649 intraVerifyDebugInfoItem, sizeof(u1), &lastOffset,
2653 case kDexTypeAnnotationItem: {
2654 okay = iterateDataSection(state, sectionOffset, sectionCount,
2655 intraVerifyAnnotationItem, sizeof(u1), &lastOffset,
2659 case kDexTypeEncodedArrayItem: {
2660 okay = iterateDataSection(state, sectionOffset, sectionCount,
2661 intraVerifyEncodedArrayItem, sizeof(u1), &lastOffset,
2665 case kDexTypeAnnotationsDirectoryItem: {
2666 okay = iterateDataSection(state, sectionOffset, sectionCount,
2667 swapAnnotationsDirectoryItem, sizeof(u4), &lastOffset,
2672 ALOGE("Unknown map item type %04x", type);
2678 ALOGE("Swap of section type %04x failed", type);
2688 * Perform cross-item verification on everything that needs it. This
2689 * pass is only called after all items are byte-swapped and
2690 * intra-verified (checked for internal consistency).
2692 static bool crossVerifyEverything(CheckState* state, DexMapList* pMap)
2694 const DexMapItem* item = pMap->list;
2695 u4 count = pMap->size;
2698 while (okay && count--) {
2699 u4 sectionOffset = item->offset;
2700 u4 sectionCount = item->size;
2702 switch (item->type) {
2703 case kDexTypeHeaderItem:
2704 case kDexTypeMapList:
2705 case kDexTypeTypeList:
2706 case kDexTypeCodeItem:
2707 case kDexTypeStringDataItem:
2708 case kDexTypeDebugInfoItem:
2709 case kDexTypeAnnotationItem:
2710 case kDexTypeEncodedArrayItem: {
2711 // There is no need for cross-item verification for these.
2714 case kDexTypeStringIdItem: {
2715 okay = iterateSection(state, sectionOffset, sectionCount,
2716 crossVerifyStringIdItem, sizeof(u4), NULL);
2719 case kDexTypeTypeIdItem: {
2720 okay = iterateSection(state, sectionOffset, sectionCount,
2721 crossVerifyTypeIdItem, sizeof(u4), NULL);
2724 case kDexTypeProtoIdItem: {
2725 okay = iterateSection(state, sectionOffset, sectionCount,
2726 crossVerifyProtoIdItem, sizeof(u4), NULL);
2729 case kDexTypeFieldIdItem: {
2730 okay = iterateSection(state, sectionOffset, sectionCount,
2731 crossVerifyFieldIdItem, sizeof(u4), NULL);
2734 case kDexTypeMethodIdItem: {
2735 okay = iterateSection(state, sectionOffset, sectionCount,
2736 crossVerifyMethodIdItem, sizeof(u4), NULL);
2739 case kDexTypeClassDefItem: {
2740 // Allocate (on the stack) the "observed class_def" bits.
2741 size_t arraySize = calcDefinedClassBitsSize(state);
2742 u4 definedClassBits[arraySize];
2743 memset(definedClassBits, 0, arraySize * sizeof(u4));
2744 state->pDefinedClassBits = definedClassBits;
2746 okay = iterateSection(state, sectionOffset, sectionCount,
2747 crossVerifyClassDefItem, sizeof(u4), NULL);
2749 state->pDefinedClassBits = NULL;
2752 case kDexTypeAnnotationSetRefList: {
2753 okay = iterateSection(state, sectionOffset, sectionCount,
2754 crossVerifyAnnotationSetRefList, sizeof(u4), NULL);
2757 case kDexTypeAnnotationSetItem: {
2758 okay = iterateSection(state, sectionOffset, sectionCount,
2759 crossVerifyAnnotationSetItem, sizeof(u4), NULL);
2762 case kDexTypeClassDataItem: {
2763 okay = iterateSection(state, sectionOffset, sectionCount,
2764 crossVerifyClassDataItem, sizeof(u1), NULL);
2767 case kDexTypeAnnotationsDirectoryItem: {
2768 okay = iterateSection(state, sectionOffset, sectionCount,
2769 crossVerifyAnnotationsDirectoryItem, sizeof(u4), NULL);
2773 ALOGE("Unknown map item type %04x", item->type);
2779 ALOGE("Cross-item verify of section type %04x failed",
2789 /* (documented in header file) */
2790 bool dexHasValidMagic(const DexHeader* pHeader)
2792 const u1* magic = pHeader->magic;
2793 const u1* version = &magic[4];
2795 if (memcmp(magic, DEX_MAGIC, 4) != 0) {
2796 ALOGE("ERROR: unrecognized magic number (%02x %02x %02x %02x)",
2797 magic[0], magic[1], magic[2], magic[3]);
2801 if ((memcmp(version, DEX_MAGIC_VERS, 4) != 0) &&
2802 (memcmp(version, DEX_MAGIC_VERS_API_13, 4) != 0)) {
2804 * Magic was correct, but this is an unsupported older or
2805 * newer format variant.
2807 ALOGE("ERROR: unsupported dex version (%02x %02x %02x %02x)",
2808 version[0], version[1], version[2], version[3]);
2816 * Fix the byte ordering of all fields in the DEX file, and do
2817 * structural verification. This is only required for code that opens
2818 * "raw" DEX files, such as the DEX optimizer.
2820 * Returns 0 on success, nonzero on failure.
2822 int dexSwapAndVerify(u1* addr, int len)
2828 memset(&state, 0, sizeof(state));
2829 ALOGV("+++ swapping and verifying");
2832 * Note: The caller must have verified that "len" is at least as
2833 * large as a dex file header.
2835 pHeader = (DexHeader*) addr;
2837 if (!dexHasValidMagic(pHeader)) {
2842 int expectedLen = (int) SWAP4(pHeader->fileSize);
2843 if (len < expectedLen) {
2844 ALOGE("ERROR: Bad length: expected %d, got %d", expectedLen, len);
2846 } else if (len != expectedLen) {
2847 ALOGW("WARNING: Odd length: expected %d, got %d", expectedLen,
2855 * Compute the adler32 checksum and compare it to what's stored in
2856 * the file. This isn't free, but chances are good that we just
2857 * unpacked this from a jar file and have all of the pages sitting
2858 * in memory, so it's pretty quick.
2860 * This might be a big-endian system, so we need to do this before
2861 * we byte-swap the header.
2863 uLong adler = adler32(0L, Z_NULL, 0);
2864 const int nonSum = sizeof(pHeader->magic) + sizeof(pHeader->checksum);
2865 u4 storedFileSize = SWAP4(pHeader->fileSize);
2866 u4 expectedChecksum = SWAP4(pHeader->checksum);
2868 adler = adler32(adler, ((const u1*) pHeader) + nonSum,
2869 storedFileSize - nonSum);
2871 if (adler != expectedChecksum) {
2872 ALOGE("ERROR: bad checksum (%08lx, expected %08x)",
2873 adler, expectedChecksum);
2879 state.fileStart = addr;
2880 state.fileEnd = addr + len;
2881 state.fileLen = len;
2882 state.pDexFile = NULL;
2883 state.pDataMap = NULL;
2884 state.pDefinedClassBits = NULL;
2885 state.previousItem = NULL;
2888 * Swap the header and check the contents.
2890 okay = swapDexHeader(&state, pHeader);
2894 state.pHeader = pHeader;
2896 if (pHeader->headerSize < sizeof(DexHeader)) {
2897 ALOGE("ERROR: Small header size %d, struct %d",
2898 pHeader->headerSize, (int) sizeof(DexHeader));
2900 } else if (pHeader->headerSize > sizeof(DexHeader)) {
2901 ALOGW("WARNING: Large header size %d, struct %d",
2902 pHeader->headerSize, (int) sizeof(DexHeader));
2909 * Look for the map. Swap it and then use it to find and swap
2912 if (pHeader->mapOff != 0) {
2914 DexMapList* pDexMap = (DexMapList*) (addr + pHeader->mapOff);
2916 okay = okay && swapMap(&state, pDexMap);
2917 okay = okay && swapEverythingButHeaderAndMap(&state, pDexMap);
2919 dexFileSetupBasicPointers(&dexFile, addr);
2920 state.pDexFile = &dexFile;
2922 okay = okay && crossVerifyEverything(&state, pDexMap);
2924 ALOGE("ERROR: No map found; impossible to byte-swap and verify");
2930 ALOGE("ERROR: Byte swap + verify failed");
2933 if (state.pDataMap != NULL) {
2934 dexDataMapFree(state.pDataMap);
2937 return !okay; // 0 == success
2941 * Detect the file type of the given memory buffer via magic number.
2942 * Call dexSwapAndVerify() on an unoptimized DEX file, do nothing
2943 * but return successfully on an optimized DEX file, and report an
2944 * error for all other cases.
2946 * Returns 0 on success, nonzero on failure.
2948 int dexSwapAndVerifyIfNecessary(u1* addr, int len)
2950 if (memcmp(addr, DEX_OPT_MAGIC, 4) == 0) {
2951 // It is an optimized dex file.
2955 if (memcmp(addr, DEX_MAGIC, 4) == 0) {
2956 // It is an unoptimized dex file.
2957 return dexSwapAndVerify(addr, len);
2960 ALOGE("ERROR: Bad magic number (0x%02x %02x %02x %02x)",
2961 addr[0], addr[1], addr[2], addr[3]);