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