blob: ff47ab5d1e8edafec4f7c698cfc66ffa92d21328 [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"
Dan Bornstein9ea32b02011-03-09 17:40:41 -080025#include "DexUtf.h"
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080026#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))
46static u2 endianSwapU2(u2 value) {
47 return (value >> 8) | (value << 8);
48}
49static u4 endianSwapU4(u4 value) {
50 /* ABCD --> CDAB --> DCBA */
51 value = (value >> 16) | (value << 16);
52 return ((value & 0xff00ff00) >> 8) | ((value << 8) & 0xff00ff00);
53}
54static 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 */
Carl Shapirobfc97992011-04-27 14:16:08 -070071struct CheckState {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080072 const DexHeader* pHeader;
Dan Bornsteine02aff72010-01-26 12:58:08 -080073 const u1* fileStart;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080074 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
Dan Bornsteine02aff72010-01-26 12:58:08 -080078
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
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080086 const void* previousItem; // set during section iteration
Carl Shapirobfc97992011-04-27 14:16:08 -070087};
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080088
89/*
90 * Return the file offset of the given pointer.
91 */
92static 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 */
99static 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 */
111static 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)) {
Steve Blocke8e1ddc2012-01-05 23:21:27 +0000117 ALOGW("Bad offset range for %s: %#x..%#x", label,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800118 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) { \
Dan Bornsteina70a3d82011-04-14 13:08:06 -0700134 const u1* _startPtr = (const u1*) filePointer(state, (_start)); \
135 const u1* _endPtr = (const u1*) filePointer(state, (_end)); \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800136 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)) { \
Brian Carlstromdc7f63d2013-05-03 17:31:16 -0700190 ALOGW("Bad index: %s(%u) > %s(%u)", \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800191 #_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)) { \
Brian Carlstromdc7f63d2013-05-03 17:31:16 -0700209 ALOGW("Bad index: %s(%u) > %s(%u)", \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800210 #_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. */
233static 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. */
240static 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/*
Dan Bornsteine02aff72010-01-26 12:58:08 -0800247 * Calculate the required size (in elements) of the array pointed at by
248 * pDefinedClassBits.
249 */
250static 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 */
259static 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/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800271 * Swap the header_item.
272 */
273static bool swapDexHeader(const CheckState* state, DexHeader* pHeader)
274{
275 CHECK_PTR_RANGE(pHeader, pHeader + 1);
Dan Bornsteine02aff72010-01-26 12:58:08 -0800276
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800277 // 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) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000302 ALOGE("Unexpected endian_tag: %#x", pHeader->endianTag);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800303 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. */
323static bool checkHeaderSection(const CheckState* state, u4 sectionOffset,
324 u4 sectionCount, u4* endOffset) {
325 if (sectionCount != 1) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000326 ALOGE("Multiple header items");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800327 return false;
328 }
329
330 if (sectionOffset != 0) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000331 ALOGE("Header at %#x; not at start of file", sectionOffset);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800332 return false;
333 }
334
Dan Bornsteina70a3d82011-04-14 13:08:06 -0700335 const DexHeader* pHeader = (const DexHeader*) filePointer(state, 0);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800336 *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 */
344static 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: {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000365 ALOGE("Unknown map item type %04x", mapType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800366 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 */
375static 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 */
395static bool swapMap(CheckState* state, DexMapList* pMap)
396{
397 DexMapItem* item = pMap->list;
Andy McFaddene5058ef2009-03-30 12:56:53 -0700398 u4 count;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800399 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;
Andy McFaddene5058ef2009-03-30 12:56:53 -0700404
405 SWAP_FIELD4(pMap->size);
406 count = pMap->size;
Dan Bornsteine02aff72010-01-26 12:58:08 -0800407
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800408 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) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000419 ALOGE("Out-of-order map item: %#x then %#x",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800420 lastOffset, item->offset);
421 return false;
422 }
423
424 if (item->offset >= state->pHeader->fileSize) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000425 ALOGE("Map item after end of file: %x, size %#x",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800426 item->offset, state->pHeader->fileSize);
427 return false;
428 }
429
430 if (isDataSectionType(item->type)) {
Andy McFaddene5058ef2009-03-30 12:56:53 -0700431 u4 icount = item->size;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800432
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 */
Andy McFaddene5058ef2009-03-30 12:56:53 -0700438 if (icount > dataItemsLeft) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000439 ALOGE("Unrealistically many items in the data section: "
Dan Bornstein6f3c21f2011-05-26 12:01:03 -0700440 "at least %d", dataItemCount + icount);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800441 return false;
442 }
443
Andy McFaddene5058ef2009-03-30 12:56:53 -0700444 dataItemsLeft -= icount;
445 dataItemCount += icount;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800446 }
447
448 u4 bit = mapTypeToBitMask(item->type);
449
450 if (bit == 0) {
451 return false;
452 }
453
454 if ((usedBits & bit) != 0) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000455 ALOGE("Duplicate map section of type %#x", item->type);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800456 return false;
457 }
458
459 usedBits |= bit;
460 lastOffset = item->offset;
461 item++;
462 }
463
464 if ((usedBits & mapTypeToBitMask(kDexTypeHeaderItem)) == 0) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000465 ALOGE("Map is missing header entry");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800466 return false;
467 }
468
469 if ((usedBits & mapTypeToBitMask(kDexTypeMapList)) == 0) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000470 ALOGE("Map is missing map_list entry");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800471 return false;
472 }
473
474 if (((usedBits & mapTypeToBitMask(kDexTypeStringIdItem)) == 0)
475 && ((state->pHeader->stringIdsOff != 0)
476 || (state->pHeader->stringIdsSize != 0))) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000477 ALOGE("Map is missing string_ids entry");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800478 return false;
479 }
480
481 if (((usedBits & mapTypeToBitMask(kDexTypeTypeIdItem)) == 0)
482 && ((state->pHeader->typeIdsOff != 0)
483 || (state->pHeader->typeIdsSize != 0))) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000484 ALOGE("Map is missing type_ids entry");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800485 return false;
486 }
487
488 if (((usedBits & mapTypeToBitMask(kDexTypeProtoIdItem)) == 0)
489 && ((state->pHeader->protoIdsOff != 0)
490 || (state->pHeader->protoIdsSize != 0))) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000491 ALOGE("Map is missing proto_ids entry");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800492 return false;
493 }
494
495 if (((usedBits & mapTypeToBitMask(kDexTypeFieldIdItem)) == 0)
496 && ((state->pHeader->fieldIdsOff != 0)
497 || (state->pHeader->fieldIdsSize != 0))) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000498 ALOGE("Map is missing field_ids entry");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800499 return false;
500 }
501
502 if (((usedBits & mapTypeToBitMask(kDexTypeMethodIdItem)) == 0)
503 && ((state->pHeader->methodIdsOff != 0)
504 || (state->pHeader->methodIdsSize != 0))) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000505 ALOGE("Map is missing method_ids entry");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800506 return false;
507 }
508
509 if (((usedBits & mapTypeToBitMask(kDexTypeClassDefItem)) == 0)
510 && ((state->pHeader->classDefsOff != 0)
511 || (state->pHeader->classDefsSize != 0))) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000512 ALOGE("Map is missing class_defs entry");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800513 return false;
514 }
515
516 state->pDataMap = dexDataMapAlloc(dataItemCount);
517 if (state->pDataMap == NULL) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000518 ALOGE("Unable to allocate data map (size %#x)", dataItemCount);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800519 return false;
520 }
Dan Bornsteine02aff72010-01-26 12:58:08 -0800521
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800522 return true;
523}
524
525/* Check the map section for sanity. */
526static bool checkMapSection(const CheckState* state, u4 sectionOffset,
527 u4 sectionCount, u4* endOffset) {
528 if (sectionCount != 1) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000529 ALOGE("Multiple map list items");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800530 return false;
531 }
532
533 if (sectionOffset != state->pHeader->mapOff) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000534 ALOGE("Map not at header-defined offset: %#x, expected %#x",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800535 sectionOffset, state->pHeader->mapOff);
536 return false;
537 }
538
Dan Bornsteina70a3d82011-04-14 13:08:06 -0700539 const DexMapList* pMap = (const DexMapList*) filePointer(state, sectionOffset);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800540
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. */
547static void* swapStringIdItem(const CheckState* state, void* ptr) {
Dan Bornsteina70a3d82011-04-14 13:08:06 -0700548 DexStringId* item = (DexStringId*) ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800549
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. */
557static void* crossVerifyStringIdItem(const CheckState* state, void* ptr) {
Dan Bornsteina70a3d82011-04-14 13:08:06 -0700558 const DexStringId* item = (const DexStringId*) ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800559
560 if (!dexDataMapVerify(state->pDataMap,
561 item->stringDataOff, kDexTypeStringDataItem)) {
562 return NULL;
563 }
564
Dan Bornsteina70a3d82011-04-14 13:08:06 -0700565 const DexStringId* item0 = (const DexStringId*) state->previousItem;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800566 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) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000571 ALOGE("Out-of-order string_ids: '%s' then '%s'", s0, s1);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800572 return NULL;
573 }
574 }
575
576 return (void*) (item + 1);
577}
578
579/* Perform byte-swapping and intra-item verification on type_id_item. */
580static void* swapTypeIdItem(const CheckState* state, void* ptr) {
Dan Bornsteina70a3d82011-04-14 13:08:06 -0700581 DexTypeId* item = (DexTypeId*) ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800582
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. */
590static void* crossVerifyTypeIdItem(const CheckState* state, void* ptr) {
Dan Bornsteina70a3d82011-04-14 13:08:06 -0700591 const DexTypeId* item = (const DexTypeId*) ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800592 const char* descriptor =
593 dexStringById(state->pDexFile, item->descriptorIdx);
594
595 if (!dexIsValidTypeDescriptor(descriptor)) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000596 ALOGE("Invalid type descriptor: '%s'", descriptor);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800597 return NULL;
598 }
599
Dan Bornsteina70a3d82011-04-14 13:08:06 -0700600 const DexTypeId* item0 = (const DexTypeId*) state->previousItem;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800601 if (item0 != NULL) {
602 // Check ordering. This relies on string_ids being in order.
603 if (item0->descriptorIdx >= item->descriptorIdx) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000604 ALOGE("Out-of-order type_ids: %#x then %#x",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800605 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. */
614static void* swapProtoIdItem(const CheckState* state, void* ptr) {
Dan Bornsteina70a3d82011-04-14 13:08:06 -0700615 DexProtoId* item = (DexProtoId*) ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800616
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. */
628static bool shortyDescMatch(char shorty, const char* descriptor, bool
629 isReturnType) {
630 switch (shorty) {
631 case 'V': {
632 if (!isReturnType) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000633 ALOGE("Invalid use of void");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800634 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')) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000647 ALOGE("Shorty vs. primitive type mismatch: '%c', '%s'",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800648 shorty, descriptor);
649 return false;
650 }
651 break;
652 }
653 case 'L': {
654 if ((descriptor[0] != 'L') && (descriptor[0] != '[')) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000655 ALOGE("Shorty vs. type mismatch: '%c', '%s'",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800656 shorty, descriptor);
657 return false;
658 }
659 break;
660 }
661 default: {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000662 ALOGE("Bogus shorty: '%c'", shorty);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800663 return false;
664 }
665 }
666
667 return true;
668}
669
670/* Perform cross-item verification of proto_id_item. */
671static void* crossVerifyProtoIdItem(const CheckState* state, void* ptr) {
Dan Bornsteina70a3d82011-04-14 13:08:06 -0700672 const DexProtoId* item = (const DexProtoId*) ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800673 const char* shorty =
674 dexStringById(state->pDexFile, item->shortyIdx);
675
676 if (!dexDataMapVerify0Ok(state->pDataMap,
677 item->parametersOff, kDexTypeTypeList)) {
678 return NULL;
679 }
Dan Bornsteine02aff72010-01-26 12:58:08 -0800680
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800681 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') {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000702 ALOGE("Shorty is too short");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800703 return NULL;
704 }
705
706 if (!shortyDescMatch(*shorty, desc, false)) {
707 return NULL;
708 }
709
710 shorty++;
711 }
712
713 if (*shorty != '\0') {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000714 ALOGE("Shorty is too long");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800715 return NULL;
716 }
Dan Bornsteine02aff72010-01-26 12:58:08 -0800717
Dan Bornsteina70a3d82011-04-14 13:08:06 -0700718 const DexProtoId* item0 = (const DexProtoId*) state->previousItem;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800719 if (item0 != NULL) {
720 // Check ordering. This relies on type_ids being in order.
721 if (item0->returnTypeIdx > item->returnTypeIdx) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000722 ALOGE("Out-of-order proto_id return types");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800723 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);
Dan Bornsteine02aff72010-01-26 12:58:08 -0800735
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800736 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) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000754 ALOGE("Out-of-order proto_id arguments");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800755 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. */
764static void* swapFieldIdItem(const CheckState* state, void* ptr) {
Dan Bornsteina70a3d82011-04-14 13:08:06 -0700765 DexFieldId* item = (DexFieldId*) ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800766
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. */
776static void* crossVerifyFieldIdItem(const CheckState* state, void* ptr) {
Dan Bornsteina70a3d82011-04-14 13:08:06 -0700777 const DexFieldId* item = (const DexFieldId*) ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800778 const char* s;
Dan Bornsteine02aff72010-01-26 12:58:08 -0800779
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800780 s = dexStringByTypeIdx(state->pDexFile, item->classIdx);
781 if (!dexIsClassDescriptor(s)) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000782 ALOGE("Invalid descriptor for class_idx: '%s'", s);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800783 return NULL;
784 }
785
786 s = dexStringByTypeIdx(state->pDexFile, item->typeIdx);
787 if (!dexIsFieldDescriptor(s)) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000788 ALOGE("Invalid descriptor for type_idx: '%s'", s);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800789 return NULL;
790 }
791
792 s = dexStringById(state->pDexFile, item->nameIdx);
793 if (!dexIsValidMemberName(s)) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000794 ALOGE("Invalid name: '%s'", s);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800795 return NULL;
796 }
797
Dan Bornsteina70a3d82011-04-14 13:08:06 -0700798 const DexFieldId* item0 = (const DexFieldId*) state->previousItem;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800799 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) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000827 ALOGE("Out-of-order field_ids");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800828 return NULL;
829 }
830 }
831
832 return (void*) (item + 1);
833}
834
835/* Perform byte-swapping and intra-item verification on method_id_item. */
836static void* swapMethodIdItem(const CheckState* state, void* ptr) {
Dan Bornsteina70a3d82011-04-14 13:08:06 -0700837 DexMethodId* item = (DexMethodId*) ptr;
Dan Bornsteine02aff72010-01-26 12:58:08 -0800838
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800839 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. */
848static void* crossVerifyMethodIdItem(const CheckState* state, void* ptr) {
Dan Bornsteina70a3d82011-04-14 13:08:06 -0700849 const DexMethodId* item = (const DexMethodId*) ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800850 const char* s;
851
852 s = dexStringByTypeIdx(state->pDexFile, item->classIdx);
853 if (!dexIsReferenceDescriptor(s)) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000854 ALOGE("Invalid descriptor for class_idx: '%s'", s);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800855 return NULL;
856 }
857
858 s = dexStringById(state->pDexFile, item->nameIdx);
859 if (!dexIsValidMemberName(s)) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000860 ALOGE("Invalid name: '%s'", s);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800861 return NULL;
862 }
863
Dan Bornsteina70a3d82011-04-14 13:08:06 -0700864 const DexMethodId* item0 = (const DexMethodId*) state->previousItem;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800865 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) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000893 ALOGE("Out-of-order method_ids");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800894 return NULL;
895 }
896 }
897
898 return (void*) (item + 1);
899}
900
901/* Perform byte-swapping and intra-item verification on class_def_item. */
902static void* swapClassDefItem(const CheckState* state, void* ptr) {
Dan Bornsteina70a3d82011-04-14 13:08:06 -0700903 DexClassDef* item = (DexClassDef*) ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800904
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
Ben Gruverc2e9a5b2013-05-08 13:29:36 -0700914 if ((item->accessFlags & ~ACC_CLASS_MASK) != 0) {
Elliott Hughes4b44ea22013-08-02 15:41:00 -0700915 // The VM specification says that unknown flags should be ignored.
916 ALOGV("Bogus class access flags %x", item->accessFlags);
917 item->accessFlags &= ACC_CLASS_MASK;
Ben Gruverc2e9a5b2013-05-08 13:29:36 -0700918 }
919
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800920 return item + 1;
921}
922
923/* defined below */
924static u4 findFirstClassDataDefiner(const CheckState* state,
925 DexClassData* classData);
926static u4 findFirstAnnotationsDirectoryDefiner(const CheckState* state,
927 const DexAnnotationsDirectoryItem* dir);
928
929/* Helper for crossVerifyClassDefItem(), which checks a class_data_item to
930 * make sure all its references are to a given class. */
931static bool verifyClassDataIsForDef(const CheckState* state, u4 offset,
932 u4 definerIdx) {
933 if (offset == 0) {
934 return true;
935 }
936
Dan Bornsteina70a3d82011-04-14 13:08:06 -0700937 const u1* data = (const u1*) filePointer(state, offset);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800938 DexClassData* classData = dexReadAndVerifyClassData(&data, NULL);
939
940 if (classData == NULL) {
941 // Shouldn't happen, but bail here just in case.
942 return false;
943 }
944
945 /*
946 * The class_data_item verification ensures that
947 * it consistently refers to the same definer, so all we need to
948 * do is check the first one.
949 */
950 u4 dataDefiner = findFirstClassDataDefiner(state, classData);
951 bool result = (dataDefiner == definerIdx) || (dataDefiner == kDexNoIndex);
Dan Bornsteine02aff72010-01-26 12:58:08 -0800952
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800953 free(classData);
954 return result;
955}
956
957/* Helper for crossVerifyClassDefItem(), which checks an
958 * annotations_directory_item to make sure all its references are to a
959 * given class. */
960static bool verifyAnnotationsDirectoryIsForDef(const CheckState* state,
961 u4 offset, u4 definerIdx) {
962 if (offset == 0) {
963 return true;
964 }
965
Dan Bornsteina70a3d82011-04-14 13:08:06 -0700966 const DexAnnotationsDirectoryItem* dir =
967 (const DexAnnotationsDirectoryItem*) filePointer(state, offset);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800968 u4 annoDefiner = findFirstAnnotationsDirectoryDefiner(state, dir);
969
970 return (annoDefiner == definerIdx) || (annoDefiner == kDexNoIndex);
971}
972
973/* Perform cross-item verification of class_def_item. */
974static void* crossVerifyClassDefItem(const CheckState* state, void* ptr) {
Dan Bornsteina70a3d82011-04-14 13:08:06 -0700975 const DexClassDef* item = (const DexClassDef*) ptr;
Dan Bornsteine02aff72010-01-26 12:58:08 -0800976 u4 classIdx = item->classIdx;
977 const char* descriptor = dexStringByTypeIdx(state->pDexFile, classIdx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800978
979 if (!dexIsClassDescriptor(descriptor)) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000980 ALOGE("Invalid class: '%s'", descriptor);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800981 return NULL;
982 }
983
Dan Bornsteine02aff72010-01-26 12:58:08 -0800984 if (setDefinedClassBit(state, classIdx)) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000985 ALOGE("Duplicate class definition: '%s'", descriptor);
Dan Bornsteine02aff72010-01-26 12:58:08 -0800986 return NULL;
987 }
988
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800989 bool okay =
990 dexDataMapVerify0Ok(state->pDataMap,
991 item->interfacesOff, kDexTypeTypeList)
992 && dexDataMapVerify0Ok(state->pDataMap,
993 item->annotationsOff, kDexTypeAnnotationsDirectoryItem)
994 && dexDataMapVerify0Ok(state->pDataMap,
995 item->classDataOff, kDexTypeClassDataItem)
996 && dexDataMapVerify0Ok(state->pDataMap,
997 item->staticValuesOff, kDexTypeEncodedArrayItem);
998
999 if (!okay) {
1000 return NULL;
1001 }
1002
1003 if (item->superclassIdx != kDexNoIndex) {
1004 descriptor = dexStringByTypeIdx(state->pDexFile, item->superclassIdx);
1005 if (!dexIsClassDescriptor(descriptor)) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001006 ALOGE("Invalid superclass: '%s'", descriptor);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001007 return NULL;
1008 }
1009 }
1010
1011 const DexTypeList* interfaces =
1012 dexGetInterfacesList(state->pDexFile, item);
1013 if (interfaces != NULL) {
1014 u4 size = interfaces->size;
1015 u4 i;
1016
1017 /*
1018 * Ensure that all interfaces refer to classes (not arrays or
1019 * primitives).
1020 */
1021 for (i = 0; i < size; i++) {
1022 descriptor = dexStringByTypeIdx(state->pDexFile,
1023 dexTypeListGetIdx(interfaces, i));
1024 if (!dexIsClassDescriptor(descriptor)) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001025 ALOGE("Invalid interface: '%s'", descriptor);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001026 return NULL;
1027 }
1028 }
1029
1030 /*
1031 * Ensure that there are no duplicates. This is an O(N^2) test,
1032 * but in practice the number of interfaces implemented by any
1033 * given class is low. I will buy a milkshake for the
1034 * first person to show me a realistic case for which this test
1035 * would be unacceptably slow.
1036 */
1037 for (i = 1; i < size; i++) {
1038 u4 idx1 = dexTypeListGetIdx(interfaces, i);
1039 u4 j;
1040 for (j = 0; j < i; j++) {
1041 u4 idx2 = dexTypeListGetIdx(interfaces, j);
1042 if (idx1 == idx2) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001043 ALOGE("Duplicate interface: '%s'",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001044 dexStringByTypeIdx(state->pDexFile, idx1));
1045 return NULL;
1046 }
1047 }
1048 }
1049 }
1050
1051 if (!verifyClassDataIsForDef(state, item->classDataOff, item->classIdx)) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001052 ALOGE("Invalid class_data_item");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001053 return NULL;
1054 }
1055
1056 if (!verifyAnnotationsDirectoryIsForDef(state, item->annotationsOff,
1057 item->classIdx)) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001058 ALOGE("Invalid annotations_directory_item");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001059 return NULL;
1060 }
1061
1062 return (void*) (item + 1);
1063}
1064
1065/* Helper for swapAnnotationsDirectoryItem(), which performs
1066 * byte-swapping and intra-item verification on an
1067 * annotation_directory_item's field elements. */
1068static u1* swapFieldAnnotations(const CheckState* state, u4 count, u1* addr) {
1069 DexFieldAnnotationsItem* item = (DexFieldAnnotationsItem*) addr;
1070 bool first = true;
1071 u4 lastIdx = 0;
1072
1073 CHECK_LIST_SIZE(item, count, sizeof(DexFieldAnnotationsItem));
1074
1075 while (count--) {
1076 SWAP_INDEX4(item->fieldIdx, state->pHeader->fieldIdsSize);
1077 SWAP_OFFSET4(item->annotationsOff);
1078
1079 if (first) {
1080 first = false;
1081 } else if (lastIdx >= item->fieldIdx) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001082 ALOGE("Out-of-order field_idx: %#x then %#x", lastIdx,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001083 item->fieldIdx);
1084 return NULL;
1085 }
1086
1087 lastIdx = item->fieldIdx;
1088 item++;
1089 }
1090
1091 return (u1*) item;
1092}
1093
1094/* Helper for swapAnnotationsDirectoryItem(), which performs
1095 * byte-swapping and intra-item verification on an
1096 * annotation_directory_item's method elements. */
1097static u1* swapMethodAnnotations(const CheckState* state, u4 count, u1* addr) {
1098 DexMethodAnnotationsItem* item = (DexMethodAnnotationsItem*) addr;
1099 bool first = true;
1100 u4 lastIdx = 0;
1101
1102 CHECK_LIST_SIZE(item, count, sizeof(DexMethodAnnotationsItem));
1103
1104 while (count--) {
1105 SWAP_INDEX4(item->methodIdx, state->pHeader->methodIdsSize);
1106 SWAP_OFFSET4(item->annotationsOff);
1107
1108 if (first) {
1109 first = false;
1110 } else if (lastIdx >= item->methodIdx) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001111 ALOGE("Out-of-order method_idx: %#x then %#x", lastIdx,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001112 item->methodIdx);
1113 return NULL;
1114 }
1115
1116 lastIdx = item->methodIdx;
1117 item++;
1118 }
1119
1120 return (u1*) item;
1121}
1122
1123/* Helper for swapAnnotationsDirectoryItem(), which performs
1124 * byte-swapping and intra-item verification on an
1125 * annotation_directory_item's parameter elements. */
1126static u1* swapParameterAnnotations(const CheckState* state, u4 count,
1127 u1* addr) {
1128 DexParameterAnnotationsItem* item = (DexParameterAnnotationsItem*) addr;
1129 bool first = true;
1130 u4 lastIdx = 0;
1131
1132 CHECK_LIST_SIZE(item, count, sizeof(DexParameterAnnotationsItem));
1133
1134 while (count--) {
1135 SWAP_INDEX4(item->methodIdx, state->pHeader->methodIdsSize);
1136 SWAP_OFFSET4(item->annotationsOff);
1137
1138 if (first) {
1139 first = false;
1140 } else if (lastIdx >= item->methodIdx) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001141 ALOGE("Out-of-order method_idx: %#x then %#x", lastIdx,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001142 item->methodIdx);
1143 return NULL;
1144 }
1145
1146 lastIdx = item->methodIdx;
1147 item++;
1148 }
1149
1150 return (u1*) item;
1151}
1152
1153/* Perform byte-swapping and intra-item verification on
1154 * annotations_directory_item. */
1155static void* swapAnnotationsDirectoryItem(const CheckState* state, void* ptr) {
Dan Bornsteina70a3d82011-04-14 13:08:06 -07001156 DexAnnotationsDirectoryItem* item = (DexAnnotationsDirectoryItem*) ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001157
1158 CHECK_PTR_RANGE(item, item + 1);
1159 SWAP_OFFSET4(item->classAnnotationsOff);
1160 SWAP_FIELD4(item->fieldsSize);
1161 SWAP_FIELD4(item->methodsSize);
1162 SWAP_FIELD4(item->parametersSize);
1163
1164 u1* addr = (u1*) (item + 1);
1165
1166 if (item->fieldsSize != 0) {
1167 addr = swapFieldAnnotations(state, item->fieldsSize, addr);
1168 if (addr == NULL) {
1169 return NULL;
1170 }
1171 }
1172
1173 if (item->methodsSize != 0) {
1174 addr = swapMethodAnnotations(state, item->methodsSize, addr);
1175 if (addr == NULL) {
1176 return NULL;
1177 }
1178 }
1179
1180 if (item->parametersSize != 0) {
1181 addr = swapParameterAnnotations(state, item->parametersSize, addr);
1182 if (addr == NULL) {
1183 return NULL;
1184 }
1185 }
1186
1187 return addr;
1188}
1189
1190/* Helper for crossVerifyAnnotationsDirectoryItem(), which checks the
1191 * field elements. */
1192static const u1* crossVerifyFieldAnnotations(const CheckState* state, u4 count,
1193 const u1* addr, u4 definingClass) {
1194 const DexFieldAnnotationsItem* item = (DexFieldAnnotationsItem*) addr;
1195
1196 while (count--) {
1197 if (!verifyFieldDefiner(state, definingClass, item->fieldIdx)) {
1198 return NULL;
1199 }
1200 if (!dexDataMapVerify(state->pDataMap, item->annotationsOff,
1201 kDexTypeAnnotationSetItem)) {
1202 return NULL;
1203 }
1204 item++;
1205 }
1206
1207 return (const u1*) item;
1208}
1209
1210/* Helper for crossVerifyAnnotationsDirectoryItem(), which checks the
1211 * method elements. */
1212static const u1* crossVerifyMethodAnnotations(const CheckState* state,
1213 u4 count, const u1* addr, u4 definingClass) {
1214 const DexMethodAnnotationsItem* item = (DexMethodAnnotationsItem*) addr;
1215
1216 while (count--) {
1217 if (!verifyMethodDefiner(state, definingClass, item->methodIdx)) {
1218 return NULL;
1219 }
1220 if (!dexDataMapVerify(state->pDataMap, item->annotationsOff,
1221 kDexTypeAnnotationSetItem)) {
1222 return NULL;
1223 }
1224 item++;
1225 }
1226
1227 return (const u1*) item;
1228}
1229
1230/* Helper for crossVerifyAnnotationsDirectoryItem(), which checks the
1231 * parameter elements. */
1232static const u1* crossVerifyParameterAnnotations(const CheckState* state,
1233 u4 count, const u1* addr, u4 definingClass) {
1234 const DexParameterAnnotationsItem* item =
1235 (DexParameterAnnotationsItem*) addr;
1236
1237 while (count--) {
1238 if (!verifyMethodDefiner(state, definingClass, item->methodIdx)) {
1239 return NULL;
1240 }
1241 if (!dexDataMapVerify(state->pDataMap, item->annotationsOff,
1242 kDexTypeAnnotationSetRefList)) {
1243 return NULL;
1244 }
1245 item++;
1246 }
1247
1248 return (const u1*) item;
1249}
1250
1251/* Helper for crossVerifyClassDefItem() and
1252 * crossVerifyAnnotationsDirectoryItem(), which finds the type_idx of
1253 * the definer of the first item in the data. */
1254static u4 findFirstAnnotationsDirectoryDefiner(const CheckState* state,
1255 const DexAnnotationsDirectoryItem* dir) {
1256 if (dir->fieldsSize != 0) {
Dan Bornsteine02aff72010-01-26 12:58:08 -08001257 const DexFieldAnnotationsItem* fields =
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001258 dexGetFieldAnnotations(state->pDexFile, dir);
1259 const DexFieldId* field =
1260 dexGetFieldId(state->pDexFile, fields[0].fieldIdx);
1261 return field->classIdx;
1262 }
1263
1264 if (dir->methodsSize != 0) {
Dan Bornsteine02aff72010-01-26 12:58:08 -08001265 const DexMethodAnnotationsItem* methods =
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001266 dexGetMethodAnnotations(state->pDexFile, dir);
1267 const DexMethodId* method =
1268 dexGetMethodId(state->pDexFile, methods[0].methodIdx);
1269 return method->classIdx;
1270 }
1271
1272 if (dir->parametersSize != 0) {
Dan Bornsteine02aff72010-01-26 12:58:08 -08001273 const DexParameterAnnotationsItem* parameters =
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001274 dexGetParameterAnnotations(state->pDexFile, dir);
1275 const DexMethodId* method =
1276 dexGetMethodId(state->pDexFile, parameters[0].methodIdx);
1277 return method->classIdx;
1278 }
1279
1280 return kDexNoIndex;
1281}
1282
1283/* Perform cross-item verification of annotations_directory_item. */
1284static void* crossVerifyAnnotationsDirectoryItem(const CheckState* state,
1285 void* ptr) {
Dan Bornsteina70a3d82011-04-14 13:08:06 -07001286 const DexAnnotationsDirectoryItem* item = (const DexAnnotationsDirectoryItem*) ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001287 u4 definingClass = findFirstAnnotationsDirectoryDefiner(state, item);
1288
1289 if (!dexDataMapVerify0Ok(state->pDataMap,
1290 item->classAnnotationsOff, kDexTypeAnnotationSetItem)) {
1291 return NULL;
1292 }
1293
1294 const u1* addr = (const u1*) (item + 1);
1295
1296 if (item->fieldsSize != 0) {
1297 addr = crossVerifyFieldAnnotations(state, item->fieldsSize, addr,
1298 definingClass);
1299 if (addr == NULL) {
1300 return NULL;
1301 }
1302 }
1303
1304 if (item->methodsSize != 0) {
1305 addr = crossVerifyMethodAnnotations(state, item->methodsSize, addr,
1306 definingClass);
1307 if (addr == NULL) {
1308 return NULL;
1309 }
1310 }
1311
1312 if (item->parametersSize != 0) {
1313 addr = crossVerifyParameterAnnotations(state, item->parametersSize,
1314 addr, definingClass);
1315 if (addr == NULL) {
1316 return NULL;
1317 }
1318 }
1319
1320 return (void*) addr;
1321}
1322
1323/* Perform byte-swapping and intra-item verification on type_list. */
1324static void* swapTypeList(const CheckState* state, void* ptr)
1325{
Dan Bornsteina70a3d82011-04-14 13:08:06 -07001326 DexTypeList* pTypeList = (DexTypeList*) ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001327 DexTypeItem* pType;
1328 u4 count;
1329
1330 CHECK_PTR_RANGE(pTypeList, pTypeList + 1);
1331 SWAP_FIELD4(pTypeList->size);
1332 count = pTypeList->size;
1333 pType = pTypeList->list;
1334 CHECK_LIST_SIZE(pType, count, sizeof(DexTypeItem));
1335
1336 while (count--) {
1337 SWAP_INDEX2(pType->typeIdx, state->pHeader->typeIdsSize);
1338 pType++;
1339 }
1340
1341 return pType;
1342}
1343
1344/* Perform byte-swapping and intra-item verification on
1345 * annotation_set_ref_list. */
1346static void* swapAnnotationSetRefList(const CheckState* state, void* ptr) {
Dan Bornsteina70a3d82011-04-14 13:08:06 -07001347 DexAnnotationSetRefList* list = (DexAnnotationSetRefList*) ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001348 DexAnnotationSetRefItem* item;
1349 u4 count;
1350
1351 CHECK_PTR_RANGE(list, list + 1);
1352 SWAP_FIELD4(list->size);
1353 count = list->size;
1354 item = list->list;
1355 CHECK_LIST_SIZE(item, count, sizeof(DexAnnotationSetRefItem));
1356
1357 while (count--) {
1358 SWAP_OFFSET4(item->annotationsOff);
1359 item++;
1360 }
1361
1362 return item;
1363}
1364
1365/* Perform cross-item verification of annotation_set_ref_list. */
1366static void* crossVerifyAnnotationSetRefList(const CheckState* state,
1367 void* ptr) {
Dan Bornsteina70a3d82011-04-14 13:08:06 -07001368 const DexAnnotationSetRefList* list = (const DexAnnotationSetRefList*) ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001369 const DexAnnotationSetRefItem* item = list->list;
1370 int count = list->size;
1371
1372 while (count--) {
1373 if (!dexDataMapVerify0Ok(state->pDataMap,
1374 item->annotationsOff, kDexTypeAnnotationSetItem)) {
1375 return NULL;
1376 }
1377 item++;
1378 }
1379
1380 return (void*) item;
1381}
1382
1383/* Perform byte-swapping and intra-item verification on
1384 * annotation_set_item. */
1385static void* swapAnnotationSetItem(const CheckState* state, void* ptr) {
Dan Bornsteina70a3d82011-04-14 13:08:06 -07001386 DexAnnotationSetItem* set = (DexAnnotationSetItem*) ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001387 u4* item;
1388 u4 count;
1389
1390 CHECK_PTR_RANGE(set, set + 1);
1391 SWAP_FIELD4(set->size);
1392 count = set->size;
1393 item = set->entries;
1394 CHECK_LIST_SIZE(item, count, sizeof(u4));
1395
1396 while (count--) {
1397 SWAP_OFFSET4(*item);
1398 item++;
1399 }
1400
1401 return item;
1402}
1403
1404/* Helper for crossVerifyAnnotationSetItem(), which extracts the type_idx
1405 * out of an annotation_item. */
1406static u4 annotationItemTypeIdx(const DexAnnotationItem* item) {
1407 const u1* data = item->annotation;
1408 return readUnsignedLeb128(&data);
1409}
Dan Bornsteine02aff72010-01-26 12:58:08 -08001410
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001411/* Perform cross-item verification of annotation_set_item. */
1412static void* crossVerifyAnnotationSetItem(const CheckState* state, void* ptr) {
Dan Bornsteina70a3d82011-04-14 13:08:06 -07001413 const DexAnnotationSetItem* set = (const DexAnnotationSetItem*) ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001414 int count = set->size;
1415 u4 lastIdx = 0;
1416 bool first = true;
1417 int i;
1418
1419 for (i = 0; i < count; i++) {
1420 if (!dexDataMapVerify0Ok(state->pDataMap,
1421 dexGetAnnotationOff(set, i), kDexTypeAnnotationItem)) {
1422 return NULL;
1423 }
Dan Bornsteine02aff72010-01-26 12:58:08 -08001424
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001425 const DexAnnotationItem* annotation =
1426 dexGetAnnotationItem(state->pDexFile, set, i);
1427 u4 idx = annotationItemTypeIdx(annotation);
1428
1429 if (first) {
1430 first = false;
1431 } else if (lastIdx >= idx) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001432 ALOGE("Out-of-order entry types: %#x then %#x",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001433 lastIdx, idx);
1434 return NULL;
1435 }
1436
1437 lastIdx = idx;
1438 }
1439
1440 return (void*) (set->entries + count);
1441}
1442
1443/* Helper for verifyClassDataItem(), which checks a list of fields. */
1444static bool verifyFields(const CheckState* state, u4 size,
1445 DexField* fields, bool expectStatic) {
1446 u4 i;
1447
1448 for (i = 0; i < size; i++) {
1449 DexField* field = &fields[i];
1450 u4 accessFlags = field->accessFlags;
1451 bool isStatic = (accessFlags & ACC_STATIC) != 0;
1452
1453 CHECK_INDEX(field->fieldIdx, state->pHeader->fieldIdsSize);
1454
1455 if (isStatic != expectStatic) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001456 ALOGE("Field in wrong list @ %d", i);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001457 return false;
1458 }
1459
1460 if ((accessFlags & ~ACC_FIELD_MASK) != 0) {
Elliott Hughes4b44ea22013-08-02 15:41:00 -07001461 // The VM specification says that unknown flags should be ignored.
1462 ALOGV("Bogus field access flags %x @ %d", accessFlags, i);
1463 field->accessFlags &= ACC_FIELD_MASK;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001464 }
1465 }
1466
1467 return true;
1468}
1469
1470/* Helper for verifyClassDataItem(), which checks a list of methods. */
1471static bool verifyMethods(const CheckState* state, u4 size,
1472 DexMethod* methods, bool expectDirect) {
1473 u4 i;
1474
1475 for (i = 0; i < size; i++) {
1476 DexMethod* method = &methods[i];
1477
1478 CHECK_INDEX(method->methodIdx, state->pHeader->methodIdsSize);
1479
1480 u4 accessFlags = method->accessFlags;
1481 bool isDirect =
1482 (accessFlags & (ACC_STATIC | ACC_PRIVATE | ACC_CONSTRUCTOR)) != 0;
1483 bool expectCode = (accessFlags & (ACC_NATIVE | ACC_ABSTRACT)) == 0;
1484 bool isSynchronized = (accessFlags & ACC_SYNCHRONIZED) != 0;
1485 bool allowSynchronized = (accessFlags & ACC_NATIVE) != 0;
1486
1487 if (isDirect != expectDirect) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001488 ALOGE("Method in wrong list @ %d", i);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001489 return false;
1490 }
1491
Elliott Hughes4b44ea22013-08-02 15:41:00 -07001492 if (isSynchronized && !allowSynchronized) {
1493 ALOGE("Bogus method access flags (synchronization) %x @ %d", accessFlags, i);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001494 return false;
1495 }
1496
Elliott Hughes4b44ea22013-08-02 15:41:00 -07001497 if ((accessFlags & ~ACC_METHOD_MASK) != 0) {
1498 // The VM specification says that unknown flags should be ignored.
1499 ALOGV("Bogus method access flags %x @ %d", accessFlags, i);
1500 method->accessFlags &= ACC_METHOD_MASK;
1501 }
1502
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001503 if (expectCode) {
1504 if (method->codeOff == 0) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001505 ALOGE("Unexpected zero code_off for access_flags %x",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001506 accessFlags);
1507 return false;
1508 }
1509 } else if (method->codeOff != 0) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001510 ALOGE("Unexpected non-zero code_off %#x for access_flags %x",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001511 method->codeOff, accessFlags);
1512 return false;
1513 }
1514 }
1515
1516 return true;
1517}
1518
1519/* Helper for verifyClassDataItem(), which does most of the work. */
1520static bool verifyClassDataItem0(const CheckState* state,
1521 DexClassData* classData) {
1522 bool okay;
Dan Bornsteine02aff72010-01-26 12:58:08 -08001523
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001524 okay = verifyFields(state, classData->header.staticFieldsSize,
1525 classData->staticFields, true);
1526
1527 if (!okay) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001528 ALOGE("Trouble with static fields");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001529 return false;
1530 }
Dan Bornsteine02aff72010-01-26 12:58:08 -08001531
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001532 verifyFields(state, classData->header.instanceFieldsSize,
1533 classData->instanceFields, false);
1534
1535 if (!okay) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001536 ALOGE("Trouble with instance fields");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001537 return false;
1538 }
1539
1540 okay = verifyMethods(state, classData->header.directMethodsSize,
1541 classData->directMethods, true);
Dan Bornsteine02aff72010-01-26 12:58:08 -08001542
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001543 if (!okay) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001544 ALOGE("Trouble with direct methods");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001545 return false;
1546 }
1547
1548 okay = verifyMethods(state, classData->header.virtualMethodsSize,
1549 classData->virtualMethods, false);
Dan Bornsteine02aff72010-01-26 12:58:08 -08001550
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001551 if (!okay) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001552 ALOGE("Trouble with virtual methods");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001553 return false;
1554 }
1555
1556 return true;
1557}
1558
1559/* Perform intra-item verification on class_data_item. */
1560static void* intraVerifyClassDataItem(const CheckState* state, void* ptr) {
Dan Bornsteina70a3d82011-04-14 13:08:06 -07001561 const u1* data = (const u1*) ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001562 DexClassData* classData = dexReadAndVerifyClassData(&data, state->fileEnd);
1563
1564 if (classData == NULL) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001565 ALOGE("Unable to parse class_data_item");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001566 return NULL;
1567 }
1568
1569 bool okay = verifyClassDataItem0(state, classData);
1570
1571 free(classData);
1572
1573 if (!okay) {
1574 return NULL;
1575 }
Dan Bornsteine02aff72010-01-26 12:58:08 -08001576
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001577 return (void*) data;
1578}
1579
1580/* Helper for crossVerifyClassDefItem() and
1581 * crossVerifyClassDataItem(), which finds the type_idx of the definer
1582 * of the first item in the data. */
1583static u4 findFirstClassDataDefiner(const CheckState* state,
1584 DexClassData* classData) {
1585 if (classData->header.staticFieldsSize != 0) {
1586 u4 fieldIdx = classData->staticFields[0].fieldIdx;
1587 const DexFieldId* field = dexGetFieldId(state->pDexFile, fieldIdx);
1588 return field->classIdx;
1589 }
1590
1591 if (classData->header.instanceFieldsSize != 0) {
1592 u4 fieldIdx = classData->instanceFields[0].fieldIdx;
1593 const DexFieldId* field = dexGetFieldId(state->pDexFile, fieldIdx);
1594 return field->classIdx;
1595 }
1596
1597 if (classData->header.directMethodsSize != 0) {
1598 u4 methodIdx = classData->directMethods[0].methodIdx;
1599 const DexMethodId* meth = dexGetMethodId(state->pDexFile, methodIdx);
1600 return meth->classIdx;
1601 }
1602
1603 if (classData->header.virtualMethodsSize != 0) {
1604 u4 methodIdx = classData->virtualMethods[0].methodIdx;
1605 const DexMethodId* meth = dexGetMethodId(state->pDexFile, methodIdx);
1606 return meth->classIdx;
1607 }
1608
1609 return kDexNoIndex;
1610}
Dan Bornsteine02aff72010-01-26 12:58:08 -08001611
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001612/* Perform cross-item verification of class_data_item. */
1613static void* crossVerifyClassDataItem(const CheckState* state, void* ptr) {
Dan Bornsteina70a3d82011-04-14 13:08:06 -07001614 const u1* data = (const u1*) ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001615 DexClassData* classData = dexReadAndVerifyClassData(&data, state->fileEnd);
1616 u4 definingClass = findFirstClassDataDefiner(state, classData);
1617 bool okay = true;
1618 u4 i;
1619
1620 for (i = classData->header.staticFieldsSize; okay && (i > 0); /*i*/) {
1621 i--;
1622 const DexField* field = &classData->staticFields[i];
1623 okay = verifyFieldDefiner(state, definingClass, field->fieldIdx);
1624 }
1625
1626 for (i = classData->header.instanceFieldsSize; okay && (i > 0); /*i*/) {
1627 i--;
1628 const DexField* field = &classData->instanceFields[i];
1629 okay = verifyFieldDefiner(state, definingClass, field->fieldIdx);
1630 }
1631
1632 for (i = classData->header.directMethodsSize; okay && (i > 0); /*i*/) {
1633 i--;
1634 const DexMethod* meth = &classData->directMethods[i];
1635 okay = dexDataMapVerify0Ok(state->pDataMap, meth->codeOff,
1636 kDexTypeCodeItem)
1637 && verifyMethodDefiner(state, definingClass, meth->methodIdx);
1638 }
1639
1640 for (i = classData->header.virtualMethodsSize; okay && (i > 0); /*i*/) {
1641 i--;
1642 const DexMethod* meth = &classData->virtualMethods[i];
1643 okay = dexDataMapVerify0Ok(state->pDataMap, meth->codeOff,
1644 kDexTypeCodeItem)
1645 && verifyMethodDefiner(state, definingClass, meth->methodIdx);
1646 }
Dan Bornsteine02aff72010-01-26 12:58:08 -08001647
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001648 free(classData);
1649
1650 if (!okay) {
1651 return NULL;
1652 }
Dan Bornsteine02aff72010-01-26 12:58:08 -08001653
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001654 return (void*) data;
1655}
1656
1657/* Helper for swapCodeItem(), which fills an array with all the valid
1658 * handlerOff values for catch handlers and also verifies the handler
1659 * contents. */
1660static u4 setHandlerOffsAndVerify(const CheckState* state,
1661 DexCode* code, u4 firstOffset, u4 handlersSize, u4* handlerOffs) {
1662 const u1* fileEnd = state->fileEnd;
1663 const u1* handlersBase = dexGetCatchHandlerData(code);
1664 u4 offset = firstOffset;
1665 bool okay = true;
1666 u4 i;
1667
1668 for (i = 0; i < handlersSize; i++) {
1669 const u1* ptr = handlersBase + offset;
1670 int size = readAndVerifySignedLeb128(&ptr, fileEnd, &okay);
1671 bool catchAll;
1672
1673 if (!okay) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001674 ALOGE("Bogus size");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001675 return 0;
1676 }
1677
1678 if ((size < -65536) || (size > 65536)) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001679 ALOGE("Invalid size: %d", size);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001680 return 0;
1681 }
1682
1683 if (size <= 0) {
1684 catchAll = true;
1685 size = -size;
1686 } else {
1687 catchAll = false;
1688 }
Dan Bornsteine02aff72010-01-26 12:58:08 -08001689
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001690 handlerOffs[i] = offset;
1691
1692 while (size-- > 0) {
1693 u4 typeIdx =
1694 readAndVerifyUnsignedLeb128(&ptr, fileEnd, &okay);
1695
1696 if (!okay) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001697 ALOGE("Bogus type_idx");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001698 return 0;
1699 }
1700
1701 CHECK_INDEX(typeIdx, state->pHeader->typeIdsSize);
1702
1703 u4 addr = readAndVerifyUnsignedLeb128(&ptr, fileEnd, &okay);
1704
1705 if (!okay) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001706 ALOGE("Bogus addr");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001707 return 0;
1708 }
1709
1710 if (addr >= code->insnsSize) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001711 ALOGE("Invalid addr: %#x", addr);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001712 return 0;
1713 }
1714 }
1715
1716 if (catchAll) {
1717 u4 addr = readAndVerifyUnsignedLeb128(&ptr, fileEnd, &okay);
1718
1719 if (!okay) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001720 ALOGE("Bogus catch_all_addr");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001721 return 0;
1722 }
1723
1724 if (addr >= code->insnsSize) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001725 ALOGE("Invalid catch_all_addr: %#x", addr);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001726 return 0;
1727 }
1728 }
1729
1730 offset = ptr - handlersBase;
1731 }
1732
1733 return offset;
1734}
1735
1736/* Helper for swapCodeItem(), which does all the try-catch related
1737 * swapping and verification. */
1738static void* swapTriesAndCatches(const CheckState* state, DexCode* code) {
1739 const u1* encodedHandlers = dexGetCatchHandlerData(code);
1740 const u1* encodedPtr = encodedHandlers;
1741 bool okay = true;
1742 u4 handlersSize =
1743 readAndVerifyUnsignedLeb128(&encodedPtr, state->fileEnd, &okay);
1744
1745 if (!okay) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001746 ALOGE("Bogus handlers_size");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001747 return NULL;
1748 }
1749
1750 if ((handlersSize == 0) || (handlersSize >= 65536)) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001751 ALOGE("Invalid handlers_size: %d", handlersSize);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001752 return NULL;
1753 }
Dan Bornsteine02aff72010-01-26 12:58:08 -08001754
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001755 u4 handlerOffs[handlersSize]; // list of valid handlerOff values
Dan Bornsteine02aff72010-01-26 12:58:08 -08001756 u4 endOffset = setHandlerOffsAndVerify(state, code,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001757 encodedPtr - encodedHandlers,
1758 handlersSize, handlerOffs);
1759
1760 if (endOffset == 0) {
1761 return NULL;
1762 }
1763
1764 DexTry* tries = (DexTry*) dexGetTries(code);
1765 u4 count = code->triesSize;
1766 u4 lastEnd = 0;
1767
1768 CHECK_LIST_SIZE(tries, count, sizeof(DexTry));
1769
1770 while (count--) {
1771 u4 i;
1772
1773 SWAP_FIELD4(tries->startAddr);
1774 SWAP_FIELD2(tries->insnCount);
1775 SWAP_FIELD2(tries->handlerOff);
1776
1777 if (tries->startAddr < lastEnd) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001778 ALOGE("Out-of-order try");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001779 return NULL;
1780 }
1781
1782 if (tries->startAddr >= code->insnsSize) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001783 ALOGE("Invalid start_addr: %#x", tries->startAddr);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001784 return NULL;
1785 }
1786
1787 for (i = 0; i < handlersSize; i++) {
1788 if (tries->handlerOff == handlerOffs[i]) {
1789 break;
1790 }
1791 }
1792
1793 if (i == handlersSize) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001794 ALOGE("Bogus handler offset: %#x", tries->handlerOff);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001795 return NULL;
1796 }
1797
1798 lastEnd = tries->startAddr + tries->insnCount;
1799
1800 if (lastEnd > code->insnsSize) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001801 ALOGE("Invalid insn_count: %#x (end addr %#x)",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001802 tries->insnCount, lastEnd);
1803 return NULL;
1804 }
Dan Bornsteine02aff72010-01-26 12:58:08 -08001805
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001806 tries++;
1807 }
1808
1809 return (u1*) encodedHandlers + endOffset;
1810}
1811
1812/* Perform byte-swapping and intra-item verification on code_item. */
1813static void* swapCodeItem(const CheckState* state, void* ptr) {
Dan Bornsteina70a3d82011-04-14 13:08:06 -07001814 DexCode* item = (DexCode*) ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001815 u2* insns;
1816 u4 count;
1817
1818 CHECK_PTR_RANGE(item, item + 1);
1819 SWAP_FIELD2(item->registersSize);
1820 SWAP_FIELD2(item->insSize);
1821 SWAP_FIELD2(item->outsSize);
1822 SWAP_FIELD2(item->triesSize);
1823 SWAP_OFFSET4(item->debugInfoOff);
1824 SWAP_FIELD4(item->insnsSize);
1825
Brian Carlstromfbdcfb92010-05-28 15:42:12 -07001826 if (item->insSize > item->registersSize) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001827 ALOGE("insSize (%u) > registersSize (%u)", item->insSize,
Brian Carlstromfbdcfb92010-05-28 15:42:12 -07001828 item->registersSize);
1829 return NULL;
1830 }
1831
1832 if ((item->outsSize > 5) && (item->outsSize > item->registersSize)) {
1833 /*
1834 * It's okay for outsSize to be up to five, even if registersSize
1835 * is smaller, since the short forms of method invocation allow
1836 * repetition of a register multiple times within a single parameter
1837 * list. Longer parameter lists, though, need to be represented
1838 * in-order in the register file.
1839 */
Steve Blockc1a4ab92012-01-06 19:16:58 +00001840 ALOGE("outsSize (%u) > registersSize (%u)", item->outsSize,
Brian Carlstromfbdcfb92010-05-28 15:42:12 -07001841 item->registersSize);
1842 return NULL;
1843 }
1844
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001845 count = item->insnsSize;
1846 insns = item->insns;
1847 CHECK_LIST_SIZE(insns, count, sizeof(u2));
1848
1849 while (count--) {
1850 *insns = SWAP2(*insns);
1851 insns++;
1852 }
1853
1854 if (item->triesSize == 0) {
1855 ptr = insns;
1856 } else {
SangWook Hanb210a9f2012-07-15 22:42:28 +09001857 if ((((uintptr_t) insns) & 3) != 0) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001858 // Four-byte alignment for the tries. Verify the spacer is a 0.
1859 if (*insns != 0) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001860 ALOGE("Non-zero padding: %#x", (u4) *insns);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001861 return NULL;
1862 }
1863 }
1864
1865 ptr = swapTriesAndCatches(state, item);
1866 }
1867
1868 return ptr;
1869}
1870
1871/* Perform intra-item verification on string_data_item. */
1872static void* intraVerifyStringDataItem(const CheckState* state, void* ptr) {
1873 const u1* fileEnd = state->fileEnd;
Dan Bornsteina70a3d82011-04-14 13:08:06 -07001874 const u1* data = (const u1*) ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001875 bool okay = true;
1876 u4 utf16Size = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
1877 u4 i;
1878
1879 if (!okay) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001880 ALOGE("Bogus utf16_size");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001881 return NULL;
1882 }
1883
1884 for (i = 0; i < utf16Size; i++) {
1885 if (data >= fileEnd) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001886 ALOGE("String data would go beyond end-of-file");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001887 return NULL;
1888 }
Dan Bornsteine02aff72010-01-26 12:58:08 -08001889
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001890 u1 byte1 = *(data++);
1891
1892 // Switch on the high four bits.
1893 switch (byte1 >> 4) {
1894 case 0x00: {
1895 // Special case of bit pattern 0xxx.
1896 if (byte1 == 0) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001897 ALOGE("String shorter than indicated utf16_size %#x",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001898 utf16Size);
1899 return NULL;
1900 }
1901 break;
1902 }
1903 case 0x01:
1904 case 0x02:
1905 case 0x03:
1906 case 0x04:
1907 case 0x05:
1908 case 0x06:
1909 case 0x07: {
1910 // Bit pattern 0xxx. No need for any extra bytes or checks.
1911 break;
1912 }
1913 case 0x08:
1914 case 0x09:
1915 case 0x0a:
1916 case 0x0b:
1917 case 0x0f: {
1918 /*
1919 * Bit pattern 10xx or 1111, which are illegal start bytes.
1920 * Note: 1111 is valid for normal UTF-8, but not the
1921 * modified UTF-8 used here.
1922 */
Steve Blockc1a4ab92012-01-06 19:16:58 +00001923 ALOGE("Illegal start byte %#x", byte1);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001924 return NULL;
1925 }
1926 case 0x0e: {
1927 // Bit pattern 1110, so there are two additional bytes.
1928 u1 byte2 = *(data++);
1929 if ((byte2 & 0xc0) != 0x80) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001930 ALOGE("Illegal continuation byte %#x", byte2);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001931 return NULL;
1932 }
1933 u1 byte3 = *(data++);
1934 if ((byte3 & 0xc0) != 0x80) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001935 ALOGE("Illegal continuation byte %#x", byte3);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001936 return NULL;
1937 }
1938 u2 value = ((byte1 & 0x0f) << 12) | ((byte2 & 0x3f) << 6)
1939 | (byte3 & 0x3f);
1940 if (value < 0x800) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001941 ALOGE("Illegal representation for value %x", value);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001942 return NULL;
1943 }
1944 break;
1945 }
1946 case 0x0c:
1947 case 0x0d: {
1948 // Bit pattern 110x, so there is one additional byte.
1949 u1 byte2 = *(data++);
1950 if ((byte2 & 0xc0) != 0x80) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001951 ALOGE("Illegal continuation byte %#x", byte2);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001952 return NULL;
1953 }
1954 u2 value = ((byte1 & 0x1f) << 6) | (byte2 & 0x3f);
1955 if ((value != 0) && (value < 0x80)) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001956 ALOGE("Illegal representation for value %x", value);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001957 return NULL;
1958 }
1959 break;
1960 }
1961 }
1962 }
1963
1964 if (*(data++) != '\0') {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001965 ALOGE("String longer than indicated utf16_size %#x", utf16Size);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001966 return NULL;
1967 }
1968
1969 return (void*) data;
1970}
1971
1972/* Perform intra-item verification on debug_info_item. */
1973static void* intraVerifyDebugInfoItem(const CheckState* state, void* ptr) {
1974 const u1* fileEnd = state->fileEnd;
Dan Bornsteina70a3d82011-04-14 13:08:06 -07001975 const u1* data = (const u1*) ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001976 bool okay = true;
1977 u4 i;
1978
1979 readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
1980
1981 if (!okay) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001982 ALOGE("Bogus line_start");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001983 return NULL;
1984 }
1985
1986 u4 parametersSize =
1987 readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
1988
1989 if (!okay) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001990 ALOGE("Bogus parameters_size");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001991 return NULL;
1992 }
1993
1994 if (parametersSize > 65536) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001995 ALOGE("Invalid parameters_size: %#x", parametersSize);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001996 return NULL;
1997 }
1998
1999 for (i = 0; i < parametersSize; i++) {
2000 u4 parameterName =
2001 readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2002
2003 if (!okay) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002004 ALOGE("Bogus parameter_name");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002005 return NULL;
2006 }
2007
2008 if (parameterName != 0) {
2009 parameterName--;
2010 CHECK_INDEX(parameterName, state->pHeader->stringIdsSize);
2011 }
2012 }
2013
2014 bool done = false;
2015 while (!done) {
2016 u1 opcode = *(data++);
2017
2018 switch (opcode) {
2019 case DBG_END_SEQUENCE: {
2020 done = true;
2021 break;
2022 }
2023 case DBG_ADVANCE_PC: {
2024 readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2025 break;
2026 }
2027 case DBG_ADVANCE_LINE: {
2028 readAndVerifySignedLeb128(&data, fileEnd, &okay);
2029 break;
2030 }
2031 case DBG_START_LOCAL: {
2032 u4 idx;
2033 u4 regNum = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2034 if (!okay) break;
2035 if (regNum >= 65536) {
2036 okay = false;
2037 break;
2038 }
2039 idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2040 if (!okay) break;
2041 if (idx != 0) {
2042 idx--;
2043 CHECK_INDEX(idx, state->pHeader->stringIdsSize);
2044 }
2045 idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2046 if (!okay) break;
2047 if (idx != 0) {
2048 idx--;
2049 CHECK_INDEX(idx, state->pHeader->stringIdsSize);
2050 }
2051 break;
2052 }
2053 case DBG_END_LOCAL:
2054 case DBG_RESTART_LOCAL: {
2055 u4 regNum = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2056 if (!okay) break;
2057 if (regNum >= 65536) {
2058 okay = false;
2059 break;
2060 }
2061 break;
2062 }
2063 case DBG_START_LOCAL_EXTENDED: {
2064 u4 idx;
2065 u4 regNum = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2066 if (!okay) break;
2067 if (regNum >= 65536) {
2068 okay = false;
2069 break;
2070 }
2071 idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2072 if (!okay) break;
2073 if (idx != 0) {
2074 idx--;
2075 CHECK_INDEX(idx, state->pHeader->stringIdsSize);
2076 }
2077 idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2078 if (!okay) break;
2079 if (idx != 0) {
2080 idx--;
2081 CHECK_INDEX(idx, state->pHeader->stringIdsSize);
2082 }
2083 idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2084 if (!okay) break;
2085 if (idx != 0) {
2086 idx--;
2087 CHECK_INDEX(idx, state->pHeader->stringIdsSize);
2088 }
2089 break;
2090 }
2091 case DBG_SET_FILE: {
2092 u4 idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2093 if (!okay) break;
2094 if (idx != 0) {
2095 idx--;
2096 CHECK_INDEX(idx, state->pHeader->stringIdsSize);
2097 }
2098 break;
2099 }
2100 default: {
2101 // No arguments to parse for anything else.
2102 }
2103 }
2104
2105 if (!okay) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002106 ALOGE("Bogus syntax for opcode %02x", opcode);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002107 return NULL;
2108 }
2109 }
Dan Bornsteine02aff72010-01-26 12:58:08 -08002110
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002111 return (void*) data;
2112}
2113
2114/* defined below */
2115static const u1* verifyEncodedValue(const CheckState* state, const u1* data,
2116 bool crossVerify);
2117static const u1* verifyEncodedAnnotation(const CheckState* state,
2118 const u1* data, bool crossVerify);
2119
2120/* Helper for verifyEncodedValue(), which reads a 1- to 4- byte unsigned
2121 * little endian value. */
2122static u4 readUnsignedLittleEndian(const CheckState* state, const u1** pData,
2123 u4 size) {
2124 const u1* data = *pData;
2125 u4 result = 0;
2126 u4 i;
2127
2128 CHECK_PTR_RANGE(data, data + size);
Dan Bornsteine02aff72010-01-26 12:58:08 -08002129
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002130 for (i = 0; i < size; i++) {
2131 result |= ((u4) *(data++)) << (i * 8);
2132 }
2133
2134 *pData = data;
Dan Bornsteine02aff72010-01-26 12:58:08 -08002135 return result;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002136}
2137
2138/* Helper for *VerifyAnnotationItem() and *VerifyEncodedArrayItem(), which
2139 * verifies an encoded_array. */
2140static const u1* verifyEncodedArray(const CheckState* state,
2141 const u1* data, bool crossVerify) {
2142 bool okay = true;
2143 u4 size = readAndVerifyUnsignedLeb128(&data, state->fileEnd, &okay);
2144
2145 if (!okay) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002146 ALOGE("Bogus encoded_array size");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002147 return NULL;
2148 }
2149
2150 while (size--) {
2151 data = verifyEncodedValue(state, data, crossVerify);
2152 if (data == NULL) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002153 ALOGE("Bogus encoded_array value");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002154 return NULL;
2155 }
2156 }
2157
2158 return data;
2159}
2160
2161/* Helper for *VerifyAnnotationItem() and *VerifyEncodedArrayItem(), which
2162 * verifies an encoded_value. */
2163static const u1* verifyEncodedValue(const CheckState* state,
2164 const u1* data, bool crossVerify) {
2165 CHECK_PTR_RANGE(data, data + 1);
Dan Bornsteine02aff72010-01-26 12:58:08 -08002166
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002167 u1 headerByte = *(data++);
2168 u4 valueType = headerByte & kDexAnnotationValueTypeMask;
2169 u4 valueArg = headerByte >> kDexAnnotationValueArgShift;
2170
2171 switch (valueType) {
2172 case kDexAnnotationByte: {
2173 if (valueArg != 0) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002174 ALOGE("Bogus byte size %#x", valueArg);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002175 return NULL;
2176 }
2177 data++;
2178 break;
2179 }
2180 case kDexAnnotationShort:
2181 case kDexAnnotationChar: {
2182 if (valueArg > 1) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002183 ALOGE("Bogus char/short size %#x", valueArg);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002184 return NULL;
2185 }
2186 data += valueArg + 1;
2187 break;
2188 }
2189 case kDexAnnotationInt:
2190 case kDexAnnotationFloat: {
2191 if (valueArg > 3) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002192 ALOGE("Bogus int/float size %#x", valueArg);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002193 return NULL;
2194 }
2195 data += valueArg + 1;
2196 break;
2197 }
2198 case kDexAnnotationLong:
2199 case kDexAnnotationDouble: {
2200 data += valueArg + 1;
2201 break;
2202 }
2203 case kDexAnnotationString: {
2204 if (valueArg > 3) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002205 ALOGE("Bogus string size %#x", valueArg);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002206 return NULL;
2207 }
2208 u4 idx = readUnsignedLittleEndian(state, &data, valueArg + 1);
2209 CHECK_INDEX(idx, state->pHeader->stringIdsSize);
2210 break;
2211 }
2212 case kDexAnnotationType: {
2213 if (valueArg > 3) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002214 ALOGE("Bogus type size %#x", valueArg);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002215 return NULL;
2216 }
2217 u4 idx = readUnsignedLittleEndian(state, &data, valueArg + 1);
2218 CHECK_INDEX(idx, state->pHeader->typeIdsSize);
2219 break;
2220 }
2221 case kDexAnnotationField:
2222 case kDexAnnotationEnum: {
2223 if (valueArg > 3) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002224 ALOGE("Bogus field/enum size %#x", valueArg);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002225 return NULL;
2226 }
2227 u4 idx = readUnsignedLittleEndian(state, &data, valueArg + 1);
2228 CHECK_INDEX(idx, state->pHeader->fieldIdsSize);
2229 break;
2230 }
2231 case kDexAnnotationMethod: {
2232 if (valueArg > 3) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002233 ALOGE("Bogus method size %#x", valueArg);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002234 return NULL;
2235 }
2236 u4 idx = readUnsignedLittleEndian(state, &data, valueArg + 1);
2237 CHECK_INDEX(idx, state->pHeader->methodIdsSize);
2238 break;
2239 }
2240 case kDexAnnotationArray: {
2241 if (valueArg != 0) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002242 ALOGE("Bogus array value_arg %#x", valueArg);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002243 return NULL;
2244 }
2245 data = verifyEncodedArray(state, data, crossVerify);
2246 break;
2247 }
2248 case kDexAnnotationAnnotation: {
2249 if (valueArg != 0) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002250 ALOGE("Bogus annotation value_arg %#x", valueArg);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002251 return NULL;
2252 }
2253 data = verifyEncodedAnnotation(state, data, crossVerify);
2254 break;
2255 }
2256 case kDexAnnotationNull: {
2257 if (valueArg != 0) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002258 ALOGE("Bogus null value_arg %#x", valueArg);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002259 return NULL;
2260 }
2261 // Nothing else to do for this type.
2262 break;
2263 }
2264 case kDexAnnotationBoolean: {
2265 if (valueArg > 1) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002266 ALOGE("Bogus boolean value_arg %#x", valueArg);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002267 return NULL;
2268 }
2269 // Nothing else to do for this type.
2270 break;
2271 }
2272 default: {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002273 ALOGE("Bogus value_type %#x", valueType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002274 return NULL;
2275 }
2276 }
2277
2278 return data;
2279}
2280
2281/* Helper for *VerifyAnnotationItem() and *VerifyEncodedArrayItem(), which
2282 * verifies an encoded_annotation. */
2283static const u1* verifyEncodedAnnotation(const CheckState* state,
2284 const u1* data, bool crossVerify) {
2285 const u1* fileEnd = state->fileEnd;
2286 bool okay = true;
2287 u4 idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2288
2289 if (!okay) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002290 ALOGE("Bogus encoded_annotation type_idx");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002291 return NULL;
2292 }
2293
2294 CHECK_INDEX(idx, state->pHeader->typeIdsSize);
2295
2296 if (crossVerify) {
2297 const char* descriptor = dexStringByTypeIdx(state->pDexFile, idx);
2298 if (!dexIsClassDescriptor(descriptor)) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002299 ALOGE("Bogus annotation type: '%s'", descriptor);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002300 return NULL;
2301 }
2302 }
Dan Bornsteine02aff72010-01-26 12:58:08 -08002303
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002304 u4 size = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2305 u4 lastIdx = 0;
2306 bool first = true;
2307
2308 if (!okay) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002309 ALOGE("Bogus encoded_annotation size");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002310 return NULL;
2311 }
2312
2313 while (size--) {
2314 idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
Dan Bornsteine02aff72010-01-26 12:58:08 -08002315
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002316 if (!okay) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002317 ALOGE("Bogus encoded_annotation name_idx");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002318 return NULL;
2319 }
2320
2321 CHECK_INDEX(idx, state->pHeader->stringIdsSize);
2322
2323 if (crossVerify) {
2324 const char* name = dexStringById(state->pDexFile, idx);
2325 if (!dexIsValidMemberName(name)) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002326 ALOGE("Bogus annotation member name: '%s'", name);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002327 return NULL;
2328 }
2329 }
2330
2331 if (first) {
2332 first = false;
2333 } else if (lastIdx >= idx) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002334 ALOGE("Out-of-order encoded_annotation name_idx: %#x then %#x",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002335 lastIdx, idx);
2336 return NULL;
2337 }
2338
2339 data = verifyEncodedValue(state, data, crossVerify);
2340 lastIdx = idx;
2341
2342 if (data == NULL) {
2343 return NULL;
2344 }
2345 }
2346
2347 return data;
2348}
2349
2350/* Perform intra-item verification on encoded_array_item. */
2351static void* intraVerifyEncodedArrayItem(const CheckState* state, void* ptr) {
2352 return (void*) verifyEncodedArray(state, (const u1*) ptr, false);
2353}
2354
2355/* Perform intra-item verification on annotation_item. */
2356static void* intraVerifyAnnotationItem(const CheckState* state, void* ptr) {
Dan Bornsteina70a3d82011-04-14 13:08:06 -07002357 const u1* data = (const u1*) ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002358
2359 CHECK_PTR_RANGE(data, data + 1);
Dan Bornsteine02aff72010-01-26 12:58:08 -08002360
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002361 switch (*(data++)) {
2362 case kDexVisibilityBuild:
2363 case kDexVisibilityRuntime:
2364 case kDexVisibilitySystem: {
2365 break;
2366 }
2367 default: {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002368 ALOGE("Bogus annotation visibility: %#x", *data);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002369 return NULL;
2370 }
2371 }
2372
2373 return (void*) verifyEncodedAnnotation(state, data, false);
2374}
2375
2376/* Perform cross-item verification on annotation_item. */
2377static void* crossVerifyAnnotationItem(const CheckState* state, void* ptr) {
Dan Bornsteina70a3d82011-04-14 13:08:06 -07002378 const u1* data = (const u1*) ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002379
2380 // Skip the visibility byte.
2381 data++;
2382
2383 return (void*) verifyEncodedAnnotation(state, data, true);
2384}
2385
2386
2387
2388
2389/*
2390 * Function to visit an individual top-level item type.
2391 */
2392typedef void* ItemVisitorFunction(const CheckState* state, void* ptr);
2393
2394/*
2395 * Iterate over all the items in a section, optionally updating the
2396 * data map (done if mapType is passed as non-negative). The section
2397 * must consist of concatenated items of the same type.
2398 */
2399static bool iterateSectionWithOptionalUpdate(CheckState* state,
2400 u4 offset, u4 count, ItemVisitorFunction* func, u4 alignment,
2401 u4* nextOffset, int mapType) {
2402 u4 alignmentMask = alignment - 1;
2403 u4 i;
2404
2405 state->previousItem = NULL;
Dan Bornsteine02aff72010-01-26 12:58:08 -08002406
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002407 for (i = 0; i < count; i++) {
2408 u4 newOffset = (offset + alignmentMask) & ~alignmentMask;
Dan Bornsteina70a3d82011-04-14 13:08:06 -07002409 u1* ptr = (u1*) filePointer(state, newOffset);
Dan Bornsteine02aff72010-01-26 12:58:08 -08002410
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002411 if (offset < newOffset) {
Dan Bornsteina70a3d82011-04-14 13:08:06 -07002412 ptr = (u1*) filePointer(state, offset);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002413 if (offset < newOffset) {
2414 CHECK_OFFSET_RANGE(offset, newOffset);
2415 while (offset < newOffset) {
2416 if (*ptr != '\0') {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002417 ALOGE("Non-zero padding 0x%02x @ %x", *ptr, offset);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002418 return false;
2419 }
2420 ptr++;
2421 offset++;
2422 }
2423 }
2424 }
2425
2426 u1* newPtr = (u1*) func(state, ptr);
2427 newOffset = fileOffset(state, newPtr);
2428
2429 if (newPtr == NULL) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002430 ALOGE("Trouble with item %d @ offset %#x", i, offset);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002431 return false;
2432 }
2433
2434 if (newOffset > state->fileLen) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002435 ALOGE("Item %d @ offset %#x ends out of bounds", i, offset);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002436 return false;
2437 }
2438
2439 if (mapType >= 0) {
2440 dexDataMapAdd(state->pDataMap, offset, mapType);
2441 }
2442
2443 state->previousItem = ptr;
2444 offset = newOffset;
2445 }
2446
2447 if (nextOffset != NULL) {
2448 *nextOffset = offset;
2449 }
2450
2451 return true;
2452}
2453
2454/*
2455 * Iterate over all the items in a section. The section must consist of
2456 * concatenated items of the same type. This variant will not update the data
2457 * map.
2458 */
2459static bool iterateSection(CheckState* state, u4 offset, u4 count,
2460 ItemVisitorFunction* func, u4 alignment, u4* nextOffset) {
2461 return iterateSectionWithOptionalUpdate(state, offset, count, func,
2462 alignment, nextOffset, -1);
2463}
2464
2465/*
2466 * Like iterateSection(), but also check that the offset and count match
2467 * a given pair of expected values.
2468 */
2469static bool checkBoundsAndIterateSection(CheckState* state,
2470 u4 offset, u4 count, u4 expectedOffset, u4 expectedCount,
2471 ItemVisitorFunction* func, u4 alignment, u4* nextOffset) {
2472 if (offset != expectedOffset) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002473 ALOGE("Bogus offset for section: got %#x; expected %#x",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002474 offset, expectedOffset);
2475 return false;
2476 }
2477
2478 if (count != expectedCount) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002479 ALOGE("Bogus size for section: got %#x; expected %#x",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002480 count, expectedCount);
2481 return false;
2482 }
2483
2484 return iterateSection(state, offset, count, func, alignment, nextOffset);
2485}
2486
2487/*
2488 * Like iterateSection(), but also update the data section map and
2489 * check that all the items fall within the data section.
2490 */
2491static bool iterateDataSection(CheckState* state, u4 offset, u4 count,
2492 ItemVisitorFunction* func, u4 alignment, u4* nextOffset, int mapType) {
2493 u4 dataStart = state->pHeader->dataOff;
2494 u4 dataEnd = dataStart + state->pHeader->dataSize;
2495
2496 assert(nextOffset != NULL);
2497
2498 if ((offset < dataStart) || (offset >= dataEnd)) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002499 ALOGE("Bogus offset for data subsection: %#x", offset);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002500 return false;
2501 }
2502
2503 if (!iterateSectionWithOptionalUpdate(state, offset, count, func,
2504 alignment, nextOffset, mapType)) {
2505 return false;
2506 }
2507
2508 if (*nextOffset > dataEnd) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002509 ALOGE("Out-of-bounds end of data subsection: %#x", *nextOffset);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002510 return false;
2511 }
2512
2513 return true;
2514}
2515
2516/*
2517 * Byte-swap all items in the given map except the header and the map
2518 * itself, both of which should have already gotten swapped. This also
2519 * does all possible intra-item verification, that is, verification
2520 * that doesn't need to assume the sanctity of the contents of *other*
2521 * items. The intra-item limitation is because at the time an item is
2522 * asked to verify itself, it can't assume that the items it refers to
2523 * have been byte-swapped and verified.
2524 */
2525static bool swapEverythingButHeaderAndMap(CheckState* state,
2526 DexMapList* pMap) {
2527 const DexMapItem* item = pMap->list;
2528 u4 lastOffset = 0;
2529 u4 count = pMap->size;
2530 bool okay = true;
2531
2532 while (okay && count--) {
2533 u4 sectionOffset = item->offset;
2534 u4 sectionCount = item->size;
2535 u2 type = item->type;
2536
2537 if (lastOffset < sectionOffset) {
2538 CHECK_OFFSET_RANGE(lastOffset, sectionOffset);
Dan Bornsteina70a3d82011-04-14 13:08:06 -07002539 const u1* ptr = (const u1*) filePointer(state, lastOffset);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002540 while (lastOffset < sectionOffset) {
2541 if (*ptr != '\0') {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002542 ALOGE("Non-zero padding 0x%02x before section start @ %x",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002543 *ptr, lastOffset);
2544 okay = false;
2545 break;
2546 }
2547 ptr++;
2548 lastOffset++;
2549 }
2550 } else if (lastOffset > sectionOffset) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002551 ALOGE("Section overlap or out-of-order map: %x, %x",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002552 lastOffset, sectionOffset);
2553 okay = false;
2554 }
2555
2556 if (!okay) {
2557 break;
2558 }
2559
2560 switch (type) {
2561 case kDexTypeHeaderItem: {
2562 /*
2563 * The header got swapped very early on, but do some
2564 * additional sanity checking here.
2565 */
2566 okay = checkHeaderSection(state, sectionOffset, sectionCount,
2567 &lastOffset);
2568 break;
2569 }
2570 case kDexTypeStringIdItem: {
2571 okay = checkBoundsAndIterateSection(state, sectionOffset,
2572 sectionCount, state->pHeader->stringIdsOff,
2573 state->pHeader->stringIdsSize, swapStringIdItem,
2574 sizeof(u4), &lastOffset);
2575 break;
2576 }
2577 case kDexTypeTypeIdItem: {
2578 okay = checkBoundsAndIterateSection(state, sectionOffset,
2579 sectionCount, state->pHeader->typeIdsOff,
2580 state->pHeader->typeIdsSize, swapTypeIdItem,
2581 sizeof(u4), &lastOffset);
2582 break;
2583 }
2584 case kDexTypeProtoIdItem: {
2585 okay = checkBoundsAndIterateSection(state, sectionOffset,
2586 sectionCount, state->pHeader->protoIdsOff,
2587 state->pHeader->protoIdsSize, swapProtoIdItem,
2588 sizeof(u4), &lastOffset);
2589 break;
2590 }
2591 case kDexTypeFieldIdItem: {
2592 okay = checkBoundsAndIterateSection(state, sectionOffset,
2593 sectionCount, state->pHeader->fieldIdsOff,
2594 state->pHeader->fieldIdsSize, swapFieldIdItem,
2595 sizeof(u4), &lastOffset);
2596 break;
2597 }
2598 case kDexTypeMethodIdItem: {
2599 okay = checkBoundsAndIterateSection(state, sectionOffset,
2600 sectionCount, state->pHeader->methodIdsOff,
2601 state->pHeader->methodIdsSize, swapMethodIdItem,
2602 sizeof(u4), &lastOffset);
2603 break;
2604 }
2605 case kDexTypeClassDefItem: {
2606 okay = checkBoundsAndIterateSection(state, sectionOffset,
2607 sectionCount, state->pHeader->classDefsOff,
2608 state->pHeader->classDefsSize, swapClassDefItem,
2609 sizeof(u4), &lastOffset);
2610 break;
2611 }
2612 case kDexTypeMapList: {
Dan Bornsteine02aff72010-01-26 12:58:08 -08002613 /*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002614 * The map section was swapped early on, but do some
2615 * additional sanity checking here.
2616 */
2617 okay = checkMapSection(state, sectionOffset, sectionCount,
2618 &lastOffset);
2619 break;
2620 }
2621 case kDexTypeTypeList: {
2622 okay = iterateDataSection(state, sectionOffset, sectionCount,
2623 swapTypeList, sizeof(u4), &lastOffset, type);
2624 break;
2625 }
2626 case kDexTypeAnnotationSetRefList: {
2627 okay = iterateDataSection(state, sectionOffset, sectionCount,
2628 swapAnnotationSetRefList, sizeof(u4), &lastOffset,
2629 type);
2630 break;
2631 }
2632 case kDexTypeAnnotationSetItem: {
2633 okay = iterateDataSection(state, sectionOffset, sectionCount,
2634 swapAnnotationSetItem, sizeof(u4), &lastOffset, type);
2635 break;
2636 }
2637 case kDexTypeClassDataItem: {
2638 okay = iterateDataSection(state, sectionOffset, sectionCount,
2639 intraVerifyClassDataItem, sizeof(u1), &lastOffset,
2640 type);
2641 break;
2642 }
2643 case kDexTypeCodeItem: {
2644 okay = iterateDataSection(state, sectionOffset, sectionCount,
2645 swapCodeItem, sizeof(u4), &lastOffset, type);
2646 break;
2647 }
2648 case kDexTypeStringDataItem: {
2649 okay = iterateDataSection(state, sectionOffset, sectionCount,
2650 intraVerifyStringDataItem, sizeof(u1), &lastOffset,
2651 type);
2652 break;
2653 }
2654 case kDexTypeDebugInfoItem: {
2655 okay = iterateDataSection(state, sectionOffset, sectionCount,
2656 intraVerifyDebugInfoItem, sizeof(u1), &lastOffset,
2657 type);
2658 break;
2659 }
2660 case kDexTypeAnnotationItem: {
2661 okay = iterateDataSection(state, sectionOffset, sectionCount,
2662 intraVerifyAnnotationItem, sizeof(u1), &lastOffset,
2663 type);
2664 break;
2665 }
2666 case kDexTypeEncodedArrayItem: {
2667 okay = iterateDataSection(state, sectionOffset, sectionCount,
2668 intraVerifyEncodedArrayItem, sizeof(u1), &lastOffset,
2669 type);
2670 break;
2671 }
2672 case kDexTypeAnnotationsDirectoryItem: {
2673 okay = iterateDataSection(state, sectionOffset, sectionCount,
2674 swapAnnotationsDirectoryItem, sizeof(u4), &lastOffset,
2675 type);
2676 break;
2677 }
2678 default: {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002679 ALOGE("Unknown map item type %04x", type);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002680 return false;
2681 }
2682 }
2683
2684 if (!okay) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002685 ALOGE("Swap of section type %04x failed", type);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002686 }
2687
2688 item++;
2689 }
2690
2691 return okay;
2692}
2693
2694/*
2695 * Perform cross-item verification on everything that needs it. This
2696 * pass is only called after all items are byte-swapped and
2697 * intra-verified (checked for internal consistency).
2698 */
2699static bool crossVerifyEverything(CheckState* state, DexMapList* pMap)
2700{
2701 const DexMapItem* item = pMap->list;
2702 u4 count = pMap->size;
2703 bool okay = true;
2704
2705 while (okay && count--) {
2706 u4 sectionOffset = item->offset;
2707 u4 sectionCount = item->size;
2708
2709 switch (item->type) {
2710 case kDexTypeHeaderItem:
2711 case kDexTypeMapList:
2712 case kDexTypeTypeList:
2713 case kDexTypeCodeItem:
2714 case kDexTypeStringDataItem:
2715 case kDexTypeDebugInfoItem:
2716 case kDexTypeAnnotationItem:
2717 case kDexTypeEncodedArrayItem: {
2718 // There is no need for cross-item verification for these.
2719 break;
2720 }
2721 case kDexTypeStringIdItem: {
2722 okay = iterateSection(state, sectionOffset, sectionCount,
2723 crossVerifyStringIdItem, sizeof(u4), NULL);
2724 break;
2725 }
2726 case kDexTypeTypeIdItem: {
2727 okay = iterateSection(state, sectionOffset, sectionCount,
2728 crossVerifyTypeIdItem, sizeof(u4), NULL);
2729 break;
2730 }
2731 case kDexTypeProtoIdItem: {
2732 okay = iterateSection(state, sectionOffset, sectionCount,
2733 crossVerifyProtoIdItem, sizeof(u4), NULL);
2734 break;
2735 }
2736 case kDexTypeFieldIdItem: {
2737 okay = iterateSection(state, sectionOffset, sectionCount,
2738 crossVerifyFieldIdItem, sizeof(u4), NULL);
2739 break;
2740 }
2741 case kDexTypeMethodIdItem: {
2742 okay = iterateSection(state, sectionOffset, sectionCount,
2743 crossVerifyMethodIdItem, sizeof(u4), NULL);
2744 break;
2745 }
2746 case kDexTypeClassDefItem: {
Dan Bornsteine02aff72010-01-26 12:58:08 -08002747 // Allocate (on the stack) the "observed class_def" bits.
2748 size_t arraySize = calcDefinedClassBitsSize(state);
2749 u4 definedClassBits[arraySize];
2750 memset(definedClassBits, 0, arraySize * sizeof(u4));
2751 state->pDefinedClassBits = definedClassBits;
2752
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002753 okay = iterateSection(state, sectionOffset, sectionCount,
2754 crossVerifyClassDefItem, sizeof(u4), NULL);
Dan Bornsteine02aff72010-01-26 12:58:08 -08002755
2756 state->pDefinedClassBits = NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002757 break;
2758 }
2759 case kDexTypeAnnotationSetRefList: {
2760 okay = iterateSection(state, sectionOffset, sectionCount,
2761 crossVerifyAnnotationSetRefList, sizeof(u4), NULL);
2762 break;
2763 }
2764 case kDexTypeAnnotationSetItem: {
2765 okay = iterateSection(state, sectionOffset, sectionCount,
2766 crossVerifyAnnotationSetItem, sizeof(u4), NULL);
2767 break;
2768 }
2769 case kDexTypeClassDataItem: {
2770 okay = iterateSection(state, sectionOffset, sectionCount,
2771 crossVerifyClassDataItem, sizeof(u1), NULL);
2772 break;
2773 }
2774 case kDexTypeAnnotationsDirectoryItem: {
2775 okay = iterateSection(state, sectionOffset, sectionCount,
2776 crossVerifyAnnotationsDirectoryItem, sizeof(u4), NULL);
2777 break;
2778 }
2779 default: {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002780 ALOGE("Unknown map item type %04x", item->type);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002781 return false;
2782 }
2783 }
2784
2785 if (!okay) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002786 ALOGE("Cross-item verify of section type %04x failed",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002787 item->type);
2788 }
2789
2790 item++;
2791 }
2792
2793 return okay;
2794}
2795
Dan Bornstein9fdbd912011-05-25 13:15:47 -07002796/* (documented in header file) */
2797bool dexHasValidMagic(const DexHeader* pHeader)
2798{
2799 const u1* magic = pHeader->magic;
2800 const u1* version = &magic[4];
2801
2802 if (memcmp(magic, DEX_MAGIC, 4) != 0) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002803 ALOGE("ERROR: unrecognized magic number (%02x %02x %02x %02x)",
Dan Bornstein9fdbd912011-05-25 13:15:47 -07002804 magic[0], magic[1], magic[2], magic[3]);
2805 return false;
2806 }
2807
2808 if ((memcmp(version, DEX_MAGIC_VERS, 4) != 0) &&
2809 (memcmp(version, DEX_MAGIC_VERS_API_13, 4) != 0)) {
2810 /*
2811 * Magic was correct, but this is an unsupported older or
2812 * newer format variant.
2813 */
Steve Blockc1a4ab92012-01-06 19:16:58 +00002814 ALOGE("ERROR: unsupported dex version (%02x %02x %02x %02x)",
Dan Bornstein9fdbd912011-05-25 13:15:47 -07002815 version[0], version[1], version[2], version[3]);
2816 return false;
2817 }
2818
2819 return true;
2820}
2821
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002822/*
Brian Carlstromfbdcfb92010-05-28 15:42:12 -07002823 * Fix the byte ordering of all fields in the DEX file, and do
2824 * structural verification. This is only required for code that opens
2825 * "raw" DEX files, such as the DEX optimizer.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002826 *
2827 * Returns 0 on success, nonzero on failure.
2828 */
Brian Carlstromfbdcfb92010-05-28 15:42:12 -07002829int dexSwapAndVerify(u1* addr, int len)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002830{
2831 DexHeader* pHeader;
2832 CheckState state;
2833 bool okay = true;
2834
2835 memset(&state, 0, sizeof(state));
Steve Block92c1f6f2011-10-20 11:55:54 +01002836 ALOGV("+++ swapping and verifying");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002837
2838 /*
Dan Bornstein9fdbd912011-05-25 13:15:47 -07002839 * Note: The caller must have verified that "len" is at least as
2840 * large as a dex file header.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002841 */
2842 pHeader = (DexHeader*) addr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002843
Dan Bornstein9fdbd912011-05-25 13:15:47 -07002844 if (!dexHasValidMagic(pHeader)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002845 okay = false;
2846 }
2847
2848 if (okay) {
2849 int expectedLen = (int) SWAP4(pHeader->fileSize);
2850 if (len < expectedLen) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002851 ALOGE("ERROR: Bad length: expected %d, got %d", expectedLen, len);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002852 okay = false;
2853 } else if (len != expectedLen) {
Steve Blocke8e1ddc2012-01-05 23:21:27 +00002854 ALOGW("WARNING: Odd length: expected %d, got %d", expectedLen,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002855 len);
2856 // keep going
2857 }
2858 }
2859
2860 if (okay) {
2861 /*
2862 * Compute the adler32 checksum and compare it to what's stored in
2863 * the file. This isn't free, but chances are good that we just
2864 * unpacked this from a jar file and have all of the pages sitting
2865 * in memory, so it's pretty quick.
2866 *
2867 * This might be a big-endian system, so we need to do this before
2868 * we byte-swap the header.
2869 */
2870 uLong adler = adler32(0L, Z_NULL, 0);
2871 const int nonSum = sizeof(pHeader->magic) + sizeof(pHeader->checksum);
2872 u4 storedFileSize = SWAP4(pHeader->fileSize);
2873 u4 expectedChecksum = SWAP4(pHeader->checksum);
2874
2875 adler = adler32(adler, ((const u1*) pHeader) + nonSum,
2876 storedFileSize - nonSum);
2877
2878 if (adler != expectedChecksum) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002879 ALOGE("ERROR: bad checksum (%08lx, expected %08x)",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002880 adler, expectedChecksum);
2881 okay = false;
2882 }
2883 }
2884
2885 if (okay) {
2886 state.fileStart = addr;
2887 state.fileEnd = addr + len;
2888 state.fileLen = len;
2889 state.pDexFile = NULL;
2890 state.pDataMap = NULL;
Dan Bornsteine02aff72010-01-26 12:58:08 -08002891 state.pDefinedClassBits = NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002892 state.previousItem = NULL;
2893
2894 /*
2895 * Swap the header and check the contents.
2896 */
2897 okay = swapDexHeader(&state, pHeader);
2898 }
2899
2900 if (okay) {
2901 state.pHeader = pHeader;
2902
2903 if (pHeader->headerSize < sizeof(DexHeader)) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002904 ALOGE("ERROR: Small header size %d, struct %d",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002905 pHeader->headerSize, (int) sizeof(DexHeader));
2906 okay = false;
2907 } else if (pHeader->headerSize > sizeof(DexHeader)) {
Steve Blocke8e1ddc2012-01-05 23:21:27 +00002908 ALOGW("WARNING: Large header size %d, struct %d",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002909 pHeader->headerSize, (int) sizeof(DexHeader));
2910 // keep going?
2911 }
2912 }
2913
2914 if (okay) {
2915 /*
2916 * Look for the map. Swap it and then use it to find and swap
2917 * everything else.
2918 */
2919 if (pHeader->mapOff != 0) {
2920 DexFile dexFile;
2921 DexMapList* pDexMap = (DexMapList*) (addr + pHeader->mapOff);
2922
2923 okay = okay && swapMap(&state, pDexMap);
2924 okay = okay && swapEverythingButHeaderAndMap(&state, pDexMap);
2925
2926 dexFileSetupBasicPointers(&dexFile, addr);
2927 state.pDexFile = &dexFile;
2928
2929 okay = okay && crossVerifyEverything(&state, pDexMap);
2930 } else {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002931 ALOGE("ERROR: No map found; impossible to byte-swap and verify");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002932 okay = false;
2933 }
2934 }
2935
2936 if (!okay) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002937 ALOGE("ERROR: Byte swap + verify failed");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002938 }
2939
2940 if (state.pDataMap != NULL) {
2941 dexDataMapFree(state.pDataMap);
2942 }
Dan Bornsteine02aff72010-01-26 12:58:08 -08002943
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002944 return !okay; // 0 == success
2945}
Brian Carlstromfbdcfb92010-05-28 15:42:12 -07002946
2947/*
2948 * Detect the file type of the given memory buffer via magic number.
2949 * Call dexSwapAndVerify() on an unoptimized DEX file, do nothing
2950 * but return successfully on an optimized DEX file, and report an
2951 * error for all other cases.
2952 *
2953 * Returns 0 on success, nonzero on failure.
2954 */
2955int dexSwapAndVerifyIfNecessary(u1* addr, int len)
2956{
2957 if (memcmp(addr, DEX_OPT_MAGIC, 4) == 0) {
2958 // It is an optimized dex file.
2959 return 0;
2960 }
2961
2962 if (memcmp(addr, DEX_MAGIC, 4) == 0) {
2963 // It is an unoptimized dex file.
2964 return dexSwapAndVerify(addr, len);
2965 }
2966
Steve Blockc1a4ab92012-01-06 19:16:58 +00002967 ALOGE("ERROR: Bad magic number (0x%02x %02x %02x %02x)",
Brian Carlstromfbdcfb92010-05-28 15:42:12 -07002968 addr[0], addr[1], addr[2], addr[3]);
2969
2970 return 1;
2971}