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