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