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