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