blob: 7f18831d6cb4ceca3b706313cbf3bd40bbec1d01 [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
Elliott Hughes50e2a582014-11-15 11:59:36 -080034#define SWAP2(_value) (_value)
35#define SWAP4(_value) (_value)
36#define SWAP8(_value) (_value)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080037
38#define SWAP_FIELD2(_field) (_field) = SWAP2(_field)
39#define SWAP_FIELD4(_field) (_field) = SWAP4(_field)
40#define SWAP_FIELD8(_field) (_field) = SWAP8(_field)
41
42/*
43 * Some information we pass around to help verify values.
44 */
Carl Shapirobfc97992011-04-27 14:16:08 -070045struct CheckState {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080046 const DexHeader* pHeader;
Dan Bornsteine02aff72010-01-26 12:58:08 -080047 const u1* fileStart;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080048 const u1* fileEnd; // points to fileStart + fileLen
49 u4 fileLen;
50 DexDataMap* pDataMap; // set after map verification
51 const DexFile* pDexFile; // set after intraitem verification
Dan Bornsteine02aff72010-01-26 12:58:08 -080052
53 /*
54 * bitmap of type_id indices that have been used to define classes;
55 * initialized immediately before class_def cross-verification, and
56 * freed immediately after it
57 */
58 u4* pDefinedClassBits;
59
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080060 const void* previousItem; // set during section iteration
Carl Shapirobfc97992011-04-27 14:16:08 -070061};
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080062
63/*
64 * Return the file offset of the given pointer.
65 */
66static inline u4 fileOffset(const CheckState* state, const void* ptr) {
67 return ((const u1*) ptr) - state->fileStart;
68}
69
70/*
71 * Return a pointer for the given file offset.
72 */
73static inline void* filePointer(const CheckState* state, u4 offset) {
74 return (void*) (state->fileStart + offset);
75}
76
77/*
78 * Verify that a pointer range, start inclusive to end exclusive, only
79 * covers bytes in the file and doesn't point beyond the end of the
80 * file. That is, the start must indicate a valid byte or may point at
81 * the byte just past the end of the file (but no further), and the
82 * end must be no less than the start and must also not point beyond
83 * the byte just past the end of the file.
84 */
85static inline bool checkPtrRange(const CheckState* state,
86 const void* start, const void* end, const char* label) {
87 const void* fileStart = state->fileStart;
88 const void* fileEnd = state->fileEnd;
89 if ((start < fileStart) || (start > fileEnd)
90 || (end < start) || (end > fileEnd)) {
Steve Blocke8e1ddc2012-01-05 23:21:27 +000091 ALOGW("Bad offset range for %s: %#x..%#x", label,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -080092 fileOffset(state, start), fileOffset(state, end));
93 return false;
94 }
95 return true;
96}
97
98/*
99 * Verify that a range of offsets, start inclusive to end exclusive,
100 * are all valid. That is, the start must indicate a valid byte or may
101 * point at the byte just past the end of the file (but no further),
102 * and the end must be no less than the start and must also not point
103 * beyond the byte just past the end of the file.
104 *
105 * Assumes "const CheckState* state".
106 */
107#define CHECK_OFFSET_RANGE(_start, _end) { \
Dan Bornsteina70a3d82011-04-14 13:08:06 -0700108 const u1* _startPtr = (const u1*) filePointer(state, (_start)); \
109 const u1* _endPtr = (const u1*) filePointer(state, (_end)); \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800110 if (!checkPtrRange(state, _startPtr, _endPtr, \
111 #_start ".." #_end)) { \
112 return 0; \
113 } \
114 }
115
116/*
117 * Verify that a pointer range, start inclusive to end exclusive, only
118 * covers bytes in the file and doesn't point beyond the end of the
119 * file. That is, the start must indicate a valid byte or may point at
120 * the byte just past the end of the file (but no further), and the
121 * end must be no less than the start and must also not point beyond
122 * the byte just past the end of the file.
123 *
124 * Assumes "const CheckState* state".
125 */
126#define CHECK_PTR_RANGE(_start, _end) { \
127 if (!checkPtrRange(state, (_start), (_end), #_start ".." #_end)) { \
128 return 0; \
129 } \
130 }
131
132/*
133 * Make sure a list of items fits entirely within the file.
134 *
135 * Assumes "const CheckState* state" and "typeof(_count) == typeof(_elemSize)"
136 * If the type sizes or signs are mismatched, this will return 0.
137 */
138#define CHECK_LIST_SIZE(_ptr, _count, _elemSize) { \
139 const u1* _start = (const u1*) (_ptr); \
140 const u1* _end = _start + ((_count) * (_elemSize)); \
141 if (!safe_mul(NULL, (_count), (_elemSize)) || \
142 !checkPtrRange(state, _start, _end, #_ptr)) { \
143 return 0; \
144 } \
145 }
146
147/*
148 * Swap a field that is known to hold an absolute DEX file offset. Note:
149 * This does not check to see that the swapped offset points within the
150 * mapped file, since that should be handled (with even more rigor) by
151 * the cross-verification phase.
152 *
153 * Assumes "const CheckState* state".
154 */
155#define SWAP_OFFSET4(_field) { \
156 SWAP_FIELD4((_field)); \
157 }
158
159/*
160 * Verify that an index falls in a valid range.
161 */
162#define CHECK_INDEX(_field, _limit) { \
163 if ((_field) >= (_limit)) { \
Brian Carlstromdc7f63d2013-05-03 17:31:16 -0700164 ALOGW("Bad index: %s(%u) > %s(%u)", \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800165 #_field, (u4)(_field), #_limit, (u4)(_limit)); \
166 return 0; \
167 } \
168 }
169
170/*
171 * Swap an index, and verify that it falls in a valid range.
172 */
173#define SWAP_INDEX2(_field, _limit) { \
174 SWAP_FIELD2((_field)); \
175 CHECK_INDEX((_field), (_limit)); \
176 }
177
178/*
179 * Verify that an index falls in a valid range or is kDexNoIndex.
180 */
181#define CHECK_INDEX_OR_NOINDEX(_field, _limit) { \
182 if ((_field) != kDexNoIndex && (_field) >= (_limit)) { \
Brian Carlstromdc7f63d2013-05-03 17:31:16 -0700183 ALOGW("Bad index: %s(%u) > %s(%u)", \
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800184 #_field, (u4)(_field), #_limit, (u4)(_limit)); \
185 return 0; \
186 } \
187 }
188
189/*
190 * Swap an index, and verify that it falls in a valid range.
191 */
192#define SWAP_INDEX4(_field, _limit) { \
193 SWAP_FIELD4((_field)); \
194 CHECK_INDEX((_field), (_limit)); \
195 }
196
197/*
198 * Swap an index, and verify that it falls in a valid range or is
199 * kDexNoIndex.
200 */
201#define SWAP_INDEX4_OR_NOINDEX(_field, _limit) { \
202 SWAP_FIELD4((_field)); \
203 CHECK_INDEX_OR_NOINDEX((_field), (_limit)); \
204 }
205
206/* Verify the definer of a given field_idx. */
207static bool verifyFieldDefiner(const CheckState* state, u4 definingClass,
208 u4 fieldIdx) {
209 const DexFieldId* field = dexGetFieldId(state->pDexFile, fieldIdx);
210 return field->classIdx == definingClass;
211}
212
213/* Verify the definer of a given method_idx. */
214static bool verifyMethodDefiner(const CheckState* state, u4 definingClass,
215 u4 methodIdx) {
216 const DexMethodId* meth = dexGetMethodId(state->pDexFile, methodIdx);
217 return meth->classIdx == definingClass;
218}
219
220/*
Dan Bornsteine02aff72010-01-26 12:58:08 -0800221 * Calculate the required size (in elements) of the array pointed at by
222 * pDefinedClassBits.
223 */
224static size_t calcDefinedClassBitsSize(const CheckState* state)
225{
226 // Divide typeIdsSize by 32 (0x20), rounding up.
227 return (state->pHeader->typeIdsSize + 0x1f) >> 5;
228}
229
230/*
231 * Set the given bit in pDefinedClassBits, returning its former value.
232 */
233static bool setDefinedClassBit(const CheckState* state, u4 typeIdx) {
234 u4 arrayIdx = typeIdx >> 5;
235 u4 bit = 1 << (typeIdx & 0x1f);
236 u4* element = &state->pDefinedClassBits[arrayIdx];
237 bool result = (*element & bit) != 0;
238
239 *element |= bit;
240
241 return result;
242}
243
244/*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800245 * Swap the header_item.
246 */
247static bool swapDexHeader(const CheckState* state, DexHeader* pHeader)
248{
249 CHECK_PTR_RANGE(pHeader, pHeader + 1);
Dan Bornsteine02aff72010-01-26 12:58:08 -0800250
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800251 // magic is ok
252 SWAP_FIELD4(pHeader->checksum);
253 // signature is ok
254 SWAP_FIELD4(pHeader->fileSize);
255 SWAP_FIELD4(pHeader->headerSize);
256 SWAP_FIELD4(pHeader->endianTag);
257 SWAP_FIELD4(pHeader->linkSize);
258 SWAP_OFFSET4(pHeader->linkOff);
259 SWAP_OFFSET4(pHeader->mapOff);
260 SWAP_FIELD4(pHeader->stringIdsSize);
261 SWAP_OFFSET4(pHeader->stringIdsOff);
262 SWAP_FIELD4(pHeader->typeIdsSize);
263 SWAP_OFFSET4(pHeader->typeIdsOff);
264 SWAP_FIELD4(pHeader->fieldIdsSize);
265 SWAP_OFFSET4(pHeader->fieldIdsOff);
266 SWAP_FIELD4(pHeader->methodIdsSize);
267 SWAP_OFFSET4(pHeader->methodIdsOff);
268 SWAP_FIELD4(pHeader->protoIdsSize);
269 SWAP_OFFSET4(pHeader->protoIdsOff);
270 SWAP_FIELD4(pHeader->classDefsSize);
271 SWAP_OFFSET4(pHeader->classDefsOff);
272 SWAP_FIELD4(pHeader->dataSize);
273 SWAP_OFFSET4(pHeader->dataOff);
274
275 if (pHeader->endianTag != kDexEndianConstant) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000276 ALOGE("Unexpected endian_tag: %#x", pHeader->endianTag);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800277 return false;
278 }
279
280 // Assign variables so the diagnostic is prettier. (Hooray for macros.)
281 u4 linkOff = pHeader->linkOff;
282 u4 linkEnd = linkOff + pHeader->linkSize;
283 u4 dataOff = pHeader->dataOff;
284 u4 dataEnd = dataOff + pHeader->dataSize;
285 CHECK_OFFSET_RANGE(linkOff, linkEnd);
286 CHECK_OFFSET_RANGE(dataOff, dataEnd);
287
288 /*
289 * Note: The offsets and ranges of the other header items end up getting
290 * checked during the first iteration over the map.
291 */
292
293 return true;
294}
295
296/* Check the header section for sanity. */
297static bool checkHeaderSection(const CheckState* state, u4 sectionOffset,
298 u4 sectionCount, u4* endOffset) {
299 if (sectionCount != 1) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000300 ALOGE("Multiple header items");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800301 return false;
302 }
303
304 if (sectionOffset != 0) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000305 ALOGE("Header at %#x; not at start of file", sectionOffset);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800306 return false;
307 }
308
Dan Bornsteina70a3d82011-04-14 13:08:06 -0700309 const DexHeader* pHeader = (const DexHeader*) filePointer(state, 0);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800310 *endOffset = pHeader->headerSize;
311 return true;
312}
313
314/*
315 * Helper for swapMap(), which turns a map type constant into a small
316 * one-bit-on integer, suitable for use in an int-sized bit set.
317 */
318static u4 mapTypeToBitMask(int mapType) {
319 switch (mapType) {
320 case kDexTypeHeaderItem: return 1 << 0;
321 case kDexTypeStringIdItem: return 1 << 1;
322 case kDexTypeTypeIdItem: return 1 << 2;
323 case kDexTypeProtoIdItem: return 1 << 3;
324 case kDexTypeFieldIdItem: return 1 << 4;
325 case kDexTypeMethodIdItem: return 1 << 5;
326 case kDexTypeClassDefItem: return 1 << 6;
327 case kDexTypeMapList: return 1 << 7;
328 case kDexTypeTypeList: return 1 << 8;
329 case kDexTypeAnnotationSetRefList: return 1 << 9;
330 case kDexTypeAnnotationSetItem: return 1 << 10;
331 case kDexTypeClassDataItem: return 1 << 11;
332 case kDexTypeCodeItem: return 1 << 12;
333 case kDexTypeStringDataItem: return 1 << 13;
334 case kDexTypeDebugInfoItem: return 1 << 14;
335 case kDexTypeAnnotationItem: return 1 << 15;
336 case kDexTypeEncodedArrayItem: return 1 << 16;
337 case kDexTypeAnnotationsDirectoryItem: return 1 << 17;
338 default: {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000339 ALOGE("Unknown map item type %04x", mapType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800340 return 0;
341 }
342 }
343}
344
345/*
346 * Helper for swapMap(), which indicates if an item type should appear
347 * in the data section.
348 */
349static bool isDataSectionType(int mapType) {
350 switch (mapType) {
351 case kDexTypeHeaderItem:
352 case kDexTypeStringIdItem:
353 case kDexTypeTypeIdItem:
354 case kDexTypeProtoIdItem:
355 case kDexTypeFieldIdItem:
356 case kDexTypeMethodIdItem:
357 case kDexTypeClassDefItem: {
358 return false;
359 }
360 }
361
362 return true;
363}
364
365/*
366 * Swap the map_list and verify what we can about it. Also, if verification
367 * passes, allocate the state's DexDataMap.
368 */
369static bool swapMap(CheckState* state, DexMapList* pMap)
370{
371 DexMapItem* item = pMap->list;
Andy McFaddene5058ef2009-03-30 12:56:53 -0700372 u4 count;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800373 u4 dataItemCount = 0; // Total count of items in the data section.
374 u4 dataItemsLeft = state->pHeader->dataSize; // See use below.
375 u4 usedBits = 0; // Bit set: one bit per section
376 bool first = true;
377 u4 lastOffset = 0;
Andy McFaddene5058ef2009-03-30 12:56:53 -0700378
379 SWAP_FIELD4(pMap->size);
380 count = pMap->size;
Dan Bornsteine02aff72010-01-26 12:58:08 -0800381
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800382 CHECK_LIST_SIZE(item, count, sizeof(DexMapItem));
383
384 while (count--) {
385 SWAP_FIELD2(item->type);
386 SWAP_FIELD2(item->unused);
387 SWAP_FIELD4(item->size);
388 SWAP_OFFSET4(item->offset);
389
390 if (first) {
391 first = false;
392 } else if (lastOffset >= item->offset) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000393 ALOGE("Out-of-order map item: %#x then %#x",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800394 lastOffset, item->offset);
395 return false;
396 }
397
398 if (item->offset >= state->pHeader->fileSize) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000399 ALOGE("Map item after end of file: %x, size %#x",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800400 item->offset, state->pHeader->fileSize);
401 return false;
402 }
403
404 if (isDataSectionType(item->type)) {
Andy McFaddene5058ef2009-03-30 12:56:53 -0700405 u4 icount = item->size;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800406
407 /*
408 * This sanity check on the data section items ensures that
409 * there are no more items than the number of bytes in
410 * the data section.
411 */
Andy McFaddene5058ef2009-03-30 12:56:53 -0700412 if (icount > dataItemsLeft) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000413 ALOGE("Unrealistically many items in the data section: "
Dan Bornstein6f3c21f2011-05-26 12:01:03 -0700414 "at least %d", dataItemCount + icount);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800415 return false;
416 }
417
Andy McFaddene5058ef2009-03-30 12:56:53 -0700418 dataItemsLeft -= icount;
419 dataItemCount += icount;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800420 }
421
422 u4 bit = mapTypeToBitMask(item->type);
423
424 if (bit == 0) {
425 return false;
426 }
427
428 if ((usedBits & bit) != 0) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000429 ALOGE("Duplicate map section of type %#x", item->type);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800430 return false;
431 }
432
433 usedBits |= bit;
434 lastOffset = item->offset;
435 item++;
436 }
437
438 if ((usedBits & mapTypeToBitMask(kDexTypeHeaderItem)) == 0) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000439 ALOGE("Map is missing header entry");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800440 return false;
441 }
442
443 if ((usedBits & mapTypeToBitMask(kDexTypeMapList)) == 0) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000444 ALOGE("Map is missing map_list entry");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800445 return false;
446 }
447
448 if (((usedBits & mapTypeToBitMask(kDexTypeStringIdItem)) == 0)
449 && ((state->pHeader->stringIdsOff != 0)
450 || (state->pHeader->stringIdsSize != 0))) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000451 ALOGE("Map is missing string_ids entry");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800452 return false;
453 }
454
455 if (((usedBits & mapTypeToBitMask(kDexTypeTypeIdItem)) == 0)
456 && ((state->pHeader->typeIdsOff != 0)
457 || (state->pHeader->typeIdsSize != 0))) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000458 ALOGE("Map is missing type_ids entry");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800459 return false;
460 }
461
462 if (((usedBits & mapTypeToBitMask(kDexTypeProtoIdItem)) == 0)
463 && ((state->pHeader->protoIdsOff != 0)
464 || (state->pHeader->protoIdsSize != 0))) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000465 ALOGE("Map is missing proto_ids entry");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800466 return false;
467 }
468
469 if (((usedBits & mapTypeToBitMask(kDexTypeFieldIdItem)) == 0)
470 && ((state->pHeader->fieldIdsOff != 0)
471 || (state->pHeader->fieldIdsSize != 0))) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000472 ALOGE("Map is missing field_ids entry");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800473 return false;
474 }
475
476 if (((usedBits & mapTypeToBitMask(kDexTypeMethodIdItem)) == 0)
477 && ((state->pHeader->methodIdsOff != 0)
478 || (state->pHeader->methodIdsSize != 0))) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000479 ALOGE("Map is missing method_ids entry");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800480 return false;
481 }
482
483 if (((usedBits & mapTypeToBitMask(kDexTypeClassDefItem)) == 0)
484 && ((state->pHeader->classDefsOff != 0)
485 || (state->pHeader->classDefsSize != 0))) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000486 ALOGE("Map is missing class_defs entry");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800487 return false;
488 }
489
490 state->pDataMap = dexDataMapAlloc(dataItemCount);
491 if (state->pDataMap == NULL) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000492 ALOGE("Unable to allocate data map (size %#x)", dataItemCount);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800493 return false;
494 }
Dan Bornsteine02aff72010-01-26 12:58:08 -0800495
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800496 return true;
497}
498
499/* Check the map section for sanity. */
500static bool checkMapSection(const CheckState* state, u4 sectionOffset,
501 u4 sectionCount, u4* endOffset) {
502 if (sectionCount != 1) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000503 ALOGE("Multiple map list items");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800504 return false;
505 }
506
507 if (sectionOffset != state->pHeader->mapOff) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000508 ALOGE("Map not at header-defined offset: %#x, expected %#x",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800509 sectionOffset, state->pHeader->mapOff);
510 return false;
511 }
512
Dan Bornsteina70a3d82011-04-14 13:08:06 -0700513 const DexMapList* pMap = (const DexMapList*) filePointer(state, sectionOffset);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800514
515 *endOffset =
516 sectionOffset + sizeof(u4) + (pMap->size * sizeof(DexMapItem));
517 return true;
518}
519
520/* Perform byte-swapping and intra-item verification on string_id_item. */
521static void* swapStringIdItem(const CheckState* state, void* ptr) {
Dan Bornsteina70a3d82011-04-14 13:08:06 -0700522 DexStringId* item = (DexStringId*) ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800523
524 CHECK_PTR_RANGE(item, item + 1);
525 SWAP_OFFSET4(item->stringDataOff);
526
527 return item + 1;
528}
529
530/* Perform cross-item verification of string_id_item. */
531static void* crossVerifyStringIdItem(const CheckState* state, void* ptr) {
Dan Bornsteina70a3d82011-04-14 13:08:06 -0700532 const DexStringId* item = (const DexStringId*) ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800533
534 if (!dexDataMapVerify(state->pDataMap,
535 item->stringDataOff, kDexTypeStringDataItem)) {
536 return NULL;
537 }
538
Dan Bornsteina70a3d82011-04-14 13:08:06 -0700539 const DexStringId* item0 = (const DexStringId*) state->previousItem;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800540 if (item0 != NULL) {
541 // Check ordering.
542 const char* s0 = dexGetStringData(state->pDexFile, item0);
543 const char* s1 = dexGetStringData(state->pDexFile, item);
544 if (dexUtf8Cmp(s0, s1) >= 0) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000545 ALOGE("Out-of-order string_ids: '%s' then '%s'", s0, s1);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800546 return NULL;
547 }
548 }
549
550 return (void*) (item + 1);
551}
552
553/* Perform byte-swapping and intra-item verification on type_id_item. */
554static void* swapTypeIdItem(const CheckState* state, void* ptr) {
Dan Bornsteina70a3d82011-04-14 13:08:06 -0700555 DexTypeId* item = (DexTypeId*) ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800556
557 CHECK_PTR_RANGE(item, item + 1);
558 SWAP_INDEX4(item->descriptorIdx, state->pHeader->stringIdsSize);
559
560 return item + 1;
561}
562
563/* Perform cross-item verification of type_id_item. */
564static void* crossVerifyTypeIdItem(const CheckState* state, void* ptr) {
Dan Bornsteina70a3d82011-04-14 13:08:06 -0700565 const DexTypeId* item = (const DexTypeId*) ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800566 const char* descriptor =
567 dexStringById(state->pDexFile, item->descriptorIdx);
568
569 if (!dexIsValidTypeDescriptor(descriptor)) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000570 ALOGE("Invalid type descriptor: '%s'", descriptor);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800571 return NULL;
572 }
573
Dan Bornsteina70a3d82011-04-14 13:08:06 -0700574 const DexTypeId* item0 = (const DexTypeId*) state->previousItem;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800575 if (item0 != NULL) {
576 // Check ordering. This relies on string_ids being in order.
577 if (item0->descriptorIdx >= item->descriptorIdx) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000578 ALOGE("Out-of-order type_ids: %#x then %#x",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800579 item0->descriptorIdx, item->descriptorIdx);
580 return NULL;
581 }
582 }
583
584 return (void*) (item + 1);
585}
586
587/* Perform byte-swapping and intra-item verification on proto_id_item. */
588static void* swapProtoIdItem(const CheckState* state, void* ptr) {
Dan Bornsteina70a3d82011-04-14 13:08:06 -0700589 DexProtoId* item = (DexProtoId*) ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800590
591 CHECK_PTR_RANGE(item, item + 1);
592 SWAP_INDEX4(item->shortyIdx, state->pHeader->stringIdsSize);
593 SWAP_INDEX4(item->returnTypeIdx, state->pHeader->typeIdsSize);
594 SWAP_OFFSET4(item->parametersOff);
595
596 return item + 1;
597}
598
599/* Helper for crossVerifyProtoIdItem(), which checks a shorty character
600 * to see if it is compatible with a type descriptor. Returns true if
601 * so, false if not. */
602static bool shortyDescMatch(char shorty, const char* descriptor, bool
603 isReturnType) {
604 switch (shorty) {
605 case 'V': {
606 if (!isReturnType) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000607 ALOGE("Invalid use of void");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800608 return false;
609 }
610 // Fall through.
611 }
612 case 'B':
613 case 'C':
614 case 'D':
615 case 'F':
616 case 'I':
617 case 'J':
618 case 'S':
619 case 'Z': {
620 if ((descriptor[0] != shorty) || (descriptor[1] != '\0')) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000621 ALOGE("Shorty vs. primitive type mismatch: '%c', '%s'",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800622 shorty, descriptor);
623 return false;
624 }
625 break;
626 }
627 case 'L': {
628 if ((descriptor[0] != 'L') && (descriptor[0] != '[')) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000629 ALOGE("Shorty vs. type mismatch: '%c', '%s'",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800630 shorty, descriptor);
631 return false;
632 }
633 break;
634 }
635 default: {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000636 ALOGE("Bogus shorty: '%c'", shorty);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800637 return false;
638 }
639 }
640
641 return true;
642}
643
644/* Perform cross-item verification of proto_id_item. */
645static void* crossVerifyProtoIdItem(const CheckState* state, void* ptr) {
Dan Bornsteina70a3d82011-04-14 13:08:06 -0700646 const DexProtoId* item = (const DexProtoId*) ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800647 const char* shorty =
648 dexStringById(state->pDexFile, item->shortyIdx);
649
650 if (!dexDataMapVerify0Ok(state->pDataMap,
651 item->parametersOff, kDexTypeTypeList)) {
652 return NULL;
653 }
Dan Bornsteine02aff72010-01-26 12:58:08 -0800654
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800655 if (!shortyDescMatch(*shorty,
656 dexStringByTypeIdx(state->pDexFile, item->returnTypeIdx),
657 true)) {
658 return NULL;
659 }
660
661 u4 protoIdx = item - state->pDexFile->pProtoIds;
662 DexProto proto = { state->pDexFile, protoIdx };
663 DexParameterIterator iterator;
664
665 dexParameterIteratorInit(&iterator, &proto);
666 shorty++; // Skip the return type.
667
668 for (;;) {
669 const char *desc = dexParameterIteratorNextDescriptor(&iterator);
670
671 if (desc == NULL) {
672 break;
673 }
674
675 if (*shorty == '\0') {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000676 ALOGE("Shorty is too short");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800677 return NULL;
678 }
679
680 if (!shortyDescMatch(*shorty, desc, false)) {
681 return NULL;
682 }
683
684 shorty++;
685 }
686
687 if (*shorty != '\0') {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000688 ALOGE("Shorty is too long");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800689 return NULL;
690 }
Dan Bornsteine02aff72010-01-26 12:58:08 -0800691
Dan Bornsteina70a3d82011-04-14 13:08:06 -0700692 const DexProtoId* item0 = (const DexProtoId*) state->previousItem;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800693 if (item0 != NULL) {
694 // Check ordering. This relies on type_ids being in order.
695 if (item0->returnTypeIdx > item->returnTypeIdx) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000696 ALOGE("Out-of-order proto_id return types");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800697 return NULL;
698 } else if (item0->returnTypeIdx == item->returnTypeIdx) {
699 bool badOrder = false;
700 DexProto proto0 = { state->pDexFile, protoIdx - 1 };
701 DexParameterIterator iterator0;
702
703 dexParameterIteratorInit(&iterator, &proto);
704 dexParameterIteratorInit(&iterator0, &proto0);
705
706 for (;;) {
707 u4 idx0 = dexParameterIteratorNextIndex(&iterator0);
708 u4 idx1 = dexParameterIteratorNextIndex(&iterator);
Dan Bornsteine02aff72010-01-26 12:58:08 -0800709
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800710 if (idx1 == kDexNoIndex) {
711 badOrder = true;
712 break;
713 }
714
715 if (idx0 == kDexNoIndex) {
716 break;
717 }
718
719 if (idx0 < idx1) {
720 break;
721 } else if (idx0 > idx1) {
722 badOrder = true;
723 break;
724 }
725 }
726
727 if (badOrder) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000728 ALOGE("Out-of-order proto_id arguments");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800729 return NULL;
730 }
731 }
732 }
733
734 return (void*) (item + 1);
735}
736
737/* Perform byte-swapping and intra-item verification on field_id_item. */
738static void* swapFieldIdItem(const CheckState* state, void* ptr) {
Dan Bornsteina70a3d82011-04-14 13:08:06 -0700739 DexFieldId* item = (DexFieldId*) ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800740
741 CHECK_PTR_RANGE(item, item + 1);
742 SWAP_INDEX2(item->classIdx, state->pHeader->typeIdsSize);
743 SWAP_INDEX2(item->typeIdx, state->pHeader->typeIdsSize);
744 SWAP_INDEX4(item->nameIdx, state->pHeader->stringIdsSize);
745
746 return item + 1;
747}
748
749/* Perform cross-item verification of field_id_item. */
750static void* crossVerifyFieldIdItem(const CheckState* state, void* ptr) {
Dan Bornsteina70a3d82011-04-14 13:08:06 -0700751 const DexFieldId* item = (const DexFieldId*) ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800752 const char* s;
Dan Bornsteine02aff72010-01-26 12:58:08 -0800753
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800754 s = dexStringByTypeIdx(state->pDexFile, item->classIdx);
755 if (!dexIsClassDescriptor(s)) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000756 ALOGE("Invalid descriptor for class_idx: '%s'", s);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800757 return NULL;
758 }
759
760 s = dexStringByTypeIdx(state->pDexFile, item->typeIdx);
761 if (!dexIsFieldDescriptor(s)) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000762 ALOGE("Invalid descriptor for type_idx: '%s'", s);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800763 return NULL;
764 }
765
766 s = dexStringById(state->pDexFile, item->nameIdx);
767 if (!dexIsValidMemberName(s)) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000768 ALOGE("Invalid name: '%s'", s);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800769 return NULL;
770 }
771
Dan Bornsteina70a3d82011-04-14 13:08:06 -0700772 const DexFieldId* item0 = (const DexFieldId*) state->previousItem;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800773 if (item0 != NULL) {
774 // Check ordering. This relies on the other sections being in order.
775 bool done = false;
776 bool bogus = false;
777
778 if (item0->classIdx > item->classIdx) {
779 bogus = true;
780 done = true;
781 } else if (item0->classIdx < item->classIdx) {
782 done = true;
783 }
784
785 if (!done) {
786 if (item0->nameIdx > item->nameIdx) {
787 bogus = true;
788 done = true;
789 } else if (item0->nameIdx < item->nameIdx) {
790 done = true;
791 }
792 }
793
794 if (!done) {
795 if (item0->typeIdx >= item->typeIdx) {
796 bogus = true;
797 }
798 }
799
800 if (bogus) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000801 ALOGE("Out-of-order field_ids");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800802 return NULL;
803 }
804 }
805
806 return (void*) (item + 1);
807}
808
809/* Perform byte-swapping and intra-item verification on method_id_item. */
810static void* swapMethodIdItem(const CheckState* state, void* ptr) {
Dan Bornsteina70a3d82011-04-14 13:08:06 -0700811 DexMethodId* item = (DexMethodId*) ptr;
Dan Bornsteine02aff72010-01-26 12:58:08 -0800812
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800813 CHECK_PTR_RANGE(item, item + 1);
814 SWAP_INDEX2(item->classIdx, state->pHeader->typeIdsSize);
815 SWAP_INDEX2(item->protoIdx, state->pHeader->protoIdsSize);
816 SWAP_INDEX4(item->nameIdx, state->pHeader->stringIdsSize);
817
818 return item + 1;
819}
820
821/* Perform cross-item verification of method_id_item. */
822static void* crossVerifyMethodIdItem(const CheckState* state, void* ptr) {
Dan Bornsteina70a3d82011-04-14 13:08:06 -0700823 const DexMethodId* item = (const DexMethodId*) ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800824 const char* s;
825
826 s = dexStringByTypeIdx(state->pDexFile, item->classIdx);
827 if (!dexIsReferenceDescriptor(s)) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000828 ALOGE("Invalid descriptor for class_idx: '%s'", s);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800829 return NULL;
830 }
831
832 s = dexStringById(state->pDexFile, item->nameIdx);
833 if (!dexIsValidMemberName(s)) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000834 ALOGE("Invalid name: '%s'", s);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800835 return NULL;
836 }
837
Dan Bornsteina70a3d82011-04-14 13:08:06 -0700838 const DexMethodId* item0 = (const DexMethodId*) state->previousItem;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800839 if (item0 != NULL) {
840 // Check ordering. This relies on the other sections being in order.
841 bool done = false;
842 bool bogus = false;
843
844 if (item0->classIdx > item->classIdx) {
845 bogus = true;
846 done = true;
847 } else if (item0->classIdx < item->classIdx) {
848 done = true;
849 }
850
851 if (!done) {
852 if (item0->nameIdx > item->nameIdx) {
853 bogus = true;
854 done = true;
855 } else if (item0->nameIdx < item->nameIdx) {
856 done = true;
857 }
858 }
859
860 if (!done) {
861 if (item0->protoIdx >= item->protoIdx) {
862 bogus = true;
863 }
864 }
865
866 if (bogus) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000867 ALOGE("Out-of-order method_ids");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800868 return NULL;
869 }
870 }
871
872 return (void*) (item + 1);
873}
874
875/* Perform byte-swapping and intra-item verification on class_def_item. */
876static void* swapClassDefItem(const CheckState* state, void* ptr) {
Dan Bornsteina70a3d82011-04-14 13:08:06 -0700877 DexClassDef* item = (DexClassDef*) ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800878
879 CHECK_PTR_RANGE(item, item + 1);
880 SWAP_INDEX4(item->classIdx, state->pHeader->typeIdsSize);
881 SWAP_FIELD4(item->accessFlags);
882 SWAP_INDEX4_OR_NOINDEX(item->superclassIdx, state->pHeader->typeIdsSize);
883 SWAP_OFFSET4(item->interfacesOff);
884 SWAP_INDEX4_OR_NOINDEX(item->sourceFileIdx, state->pHeader->stringIdsSize);
885 SWAP_OFFSET4(item->annotationsOff);
886 SWAP_OFFSET4(item->classDataOff);
887
Ben Gruverc2e9a5b2013-05-08 13:29:36 -0700888 if ((item->accessFlags & ~ACC_CLASS_MASK) != 0) {
Elliott Hughes4b44ea22013-08-02 15:41:00 -0700889 // The VM specification says that unknown flags should be ignored.
890 ALOGV("Bogus class access flags %x", item->accessFlags);
891 item->accessFlags &= ACC_CLASS_MASK;
Ben Gruverc2e9a5b2013-05-08 13:29:36 -0700892 }
893
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800894 return item + 1;
895}
896
897/* defined below */
898static u4 findFirstClassDataDefiner(const CheckState* state,
899 DexClassData* classData);
900static u4 findFirstAnnotationsDirectoryDefiner(const CheckState* state,
901 const DexAnnotationsDirectoryItem* dir);
902
903/* Helper for crossVerifyClassDefItem(), which checks a class_data_item to
904 * make sure all its references are to a given class. */
905static bool verifyClassDataIsForDef(const CheckState* state, u4 offset,
906 u4 definerIdx) {
907 if (offset == 0) {
908 return true;
909 }
910
Dan Bornsteina70a3d82011-04-14 13:08:06 -0700911 const u1* data = (const u1*) filePointer(state, offset);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800912 DexClassData* classData = dexReadAndVerifyClassData(&data, NULL);
913
914 if (classData == NULL) {
915 // Shouldn't happen, but bail here just in case.
916 return false;
917 }
918
919 /*
920 * The class_data_item verification ensures that
921 * it consistently refers to the same definer, so all we need to
922 * do is check the first one.
923 */
924 u4 dataDefiner = findFirstClassDataDefiner(state, classData);
925 bool result = (dataDefiner == definerIdx) || (dataDefiner == kDexNoIndex);
Dan Bornsteine02aff72010-01-26 12:58:08 -0800926
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800927 free(classData);
928 return result;
929}
930
931/* Helper for crossVerifyClassDefItem(), which checks an
932 * annotations_directory_item to make sure all its references are to a
933 * given class. */
934static bool verifyAnnotationsDirectoryIsForDef(const CheckState* state,
935 u4 offset, u4 definerIdx) {
936 if (offset == 0) {
937 return true;
938 }
939
Dan Bornsteina70a3d82011-04-14 13:08:06 -0700940 const DexAnnotationsDirectoryItem* dir =
941 (const DexAnnotationsDirectoryItem*) filePointer(state, offset);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800942 u4 annoDefiner = findFirstAnnotationsDirectoryDefiner(state, dir);
943
944 return (annoDefiner == definerIdx) || (annoDefiner == kDexNoIndex);
945}
946
947/* Perform cross-item verification of class_def_item. */
948static void* crossVerifyClassDefItem(const CheckState* state, void* ptr) {
Dan Bornsteina70a3d82011-04-14 13:08:06 -0700949 const DexClassDef* item = (const DexClassDef*) ptr;
Dan Bornsteine02aff72010-01-26 12:58:08 -0800950 u4 classIdx = item->classIdx;
951 const char* descriptor = dexStringByTypeIdx(state->pDexFile, classIdx);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800952
953 if (!dexIsClassDescriptor(descriptor)) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000954 ALOGE("Invalid class: '%s'", descriptor);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800955 return NULL;
956 }
957
Dan Bornsteine02aff72010-01-26 12:58:08 -0800958 if (setDefinedClassBit(state, classIdx)) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000959 ALOGE("Duplicate class definition: '%s'", descriptor);
Dan Bornsteine02aff72010-01-26 12:58:08 -0800960 return NULL;
961 }
962
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800963 bool okay =
964 dexDataMapVerify0Ok(state->pDataMap,
965 item->interfacesOff, kDexTypeTypeList)
966 && dexDataMapVerify0Ok(state->pDataMap,
967 item->annotationsOff, kDexTypeAnnotationsDirectoryItem)
968 && dexDataMapVerify0Ok(state->pDataMap,
969 item->classDataOff, kDexTypeClassDataItem)
970 && dexDataMapVerify0Ok(state->pDataMap,
971 item->staticValuesOff, kDexTypeEncodedArrayItem);
972
973 if (!okay) {
974 return NULL;
975 }
976
977 if (item->superclassIdx != kDexNoIndex) {
978 descriptor = dexStringByTypeIdx(state->pDexFile, item->superclassIdx);
979 if (!dexIsClassDescriptor(descriptor)) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000980 ALOGE("Invalid superclass: '%s'", descriptor);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -0800981 return NULL;
982 }
983 }
984
985 const DexTypeList* interfaces =
986 dexGetInterfacesList(state->pDexFile, item);
987 if (interfaces != NULL) {
988 u4 size = interfaces->size;
989 u4 i;
990
991 /*
992 * Ensure that all interfaces refer to classes (not arrays or
993 * primitives).
994 */
995 for (i = 0; i < size; i++) {
996 descriptor = dexStringByTypeIdx(state->pDexFile,
997 dexTypeListGetIdx(interfaces, i));
998 if (!dexIsClassDescriptor(descriptor)) {
Steve Blockc1a4ab92012-01-06 19:16:58 +0000999 ALOGE("Invalid interface: '%s'", descriptor);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001000 return NULL;
1001 }
1002 }
1003
1004 /*
1005 * Ensure that there are no duplicates. This is an O(N^2) test,
1006 * but in practice the number of interfaces implemented by any
1007 * given class is low. I will buy a milkshake for the
1008 * first person to show me a realistic case for which this test
1009 * would be unacceptably slow.
1010 */
1011 for (i = 1; i < size; i++) {
1012 u4 idx1 = dexTypeListGetIdx(interfaces, i);
1013 u4 j;
1014 for (j = 0; j < i; j++) {
1015 u4 idx2 = dexTypeListGetIdx(interfaces, j);
1016 if (idx1 == idx2) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001017 ALOGE("Duplicate interface: '%s'",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001018 dexStringByTypeIdx(state->pDexFile, idx1));
1019 return NULL;
1020 }
1021 }
1022 }
1023 }
1024
1025 if (!verifyClassDataIsForDef(state, item->classDataOff, item->classIdx)) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001026 ALOGE("Invalid class_data_item");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001027 return NULL;
1028 }
1029
1030 if (!verifyAnnotationsDirectoryIsForDef(state, item->annotationsOff,
1031 item->classIdx)) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001032 ALOGE("Invalid annotations_directory_item");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001033 return NULL;
1034 }
1035
1036 return (void*) (item + 1);
1037}
1038
1039/* Helper for swapAnnotationsDirectoryItem(), which performs
1040 * byte-swapping and intra-item verification on an
1041 * annotation_directory_item's field elements. */
1042static u1* swapFieldAnnotations(const CheckState* state, u4 count, u1* addr) {
1043 DexFieldAnnotationsItem* item = (DexFieldAnnotationsItem*) addr;
1044 bool first = true;
1045 u4 lastIdx = 0;
1046
1047 CHECK_LIST_SIZE(item, count, sizeof(DexFieldAnnotationsItem));
1048
1049 while (count--) {
1050 SWAP_INDEX4(item->fieldIdx, state->pHeader->fieldIdsSize);
1051 SWAP_OFFSET4(item->annotationsOff);
1052
1053 if (first) {
1054 first = false;
1055 } else if (lastIdx >= item->fieldIdx) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001056 ALOGE("Out-of-order field_idx: %#x then %#x", lastIdx,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001057 item->fieldIdx);
1058 return NULL;
1059 }
1060
1061 lastIdx = item->fieldIdx;
1062 item++;
1063 }
1064
1065 return (u1*) item;
1066}
1067
1068/* Helper for swapAnnotationsDirectoryItem(), which performs
1069 * byte-swapping and intra-item verification on an
1070 * annotation_directory_item's method elements. */
1071static u1* swapMethodAnnotations(const CheckState* state, u4 count, u1* addr) {
1072 DexMethodAnnotationsItem* item = (DexMethodAnnotationsItem*) addr;
1073 bool first = true;
1074 u4 lastIdx = 0;
1075
1076 CHECK_LIST_SIZE(item, count, sizeof(DexMethodAnnotationsItem));
1077
1078 while (count--) {
1079 SWAP_INDEX4(item->methodIdx, state->pHeader->methodIdsSize);
1080 SWAP_OFFSET4(item->annotationsOff);
1081
1082 if (first) {
1083 first = false;
1084 } else if (lastIdx >= item->methodIdx) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001085 ALOGE("Out-of-order method_idx: %#x then %#x", lastIdx,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001086 item->methodIdx);
1087 return NULL;
1088 }
1089
1090 lastIdx = item->methodIdx;
1091 item++;
1092 }
1093
1094 return (u1*) item;
1095}
1096
1097/* Helper for swapAnnotationsDirectoryItem(), which performs
1098 * byte-swapping and intra-item verification on an
1099 * annotation_directory_item's parameter elements. */
1100static u1* swapParameterAnnotations(const CheckState* state, u4 count,
1101 u1* addr) {
1102 DexParameterAnnotationsItem* item = (DexParameterAnnotationsItem*) addr;
1103 bool first = true;
1104 u4 lastIdx = 0;
1105
1106 CHECK_LIST_SIZE(item, count, sizeof(DexParameterAnnotationsItem));
1107
1108 while (count--) {
1109 SWAP_INDEX4(item->methodIdx, state->pHeader->methodIdsSize);
1110 SWAP_OFFSET4(item->annotationsOff);
1111
1112 if (first) {
1113 first = false;
1114 } else if (lastIdx >= item->methodIdx) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001115 ALOGE("Out-of-order method_idx: %#x then %#x", lastIdx,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001116 item->methodIdx);
1117 return NULL;
1118 }
1119
1120 lastIdx = item->methodIdx;
1121 item++;
1122 }
1123
1124 return (u1*) item;
1125}
1126
1127/* Perform byte-swapping and intra-item verification on
1128 * annotations_directory_item. */
1129static void* swapAnnotationsDirectoryItem(const CheckState* state, void* ptr) {
Dan Bornsteina70a3d82011-04-14 13:08:06 -07001130 DexAnnotationsDirectoryItem* item = (DexAnnotationsDirectoryItem*) ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001131
1132 CHECK_PTR_RANGE(item, item + 1);
1133 SWAP_OFFSET4(item->classAnnotationsOff);
1134 SWAP_FIELD4(item->fieldsSize);
1135 SWAP_FIELD4(item->methodsSize);
1136 SWAP_FIELD4(item->parametersSize);
1137
1138 u1* addr = (u1*) (item + 1);
1139
1140 if (item->fieldsSize != 0) {
1141 addr = swapFieldAnnotations(state, item->fieldsSize, addr);
1142 if (addr == NULL) {
1143 return NULL;
1144 }
1145 }
1146
1147 if (item->methodsSize != 0) {
1148 addr = swapMethodAnnotations(state, item->methodsSize, addr);
1149 if (addr == NULL) {
1150 return NULL;
1151 }
1152 }
1153
1154 if (item->parametersSize != 0) {
1155 addr = swapParameterAnnotations(state, item->parametersSize, addr);
1156 if (addr == NULL) {
1157 return NULL;
1158 }
1159 }
1160
1161 return addr;
1162}
1163
1164/* Helper for crossVerifyAnnotationsDirectoryItem(), which checks the
1165 * field elements. */
1166static const u1* crossVerifyFieldAnnotations(const CheckState* state, u4 count,
1167 const u1* addr, u4 definingClass) {
1168 const DexFieldAnnotationsItem* item = (DexFieldAnnotationsItem*) addr;
1169
1170 while (count--) {
1171 if (!verifyFieldDefiner(state, definingClass, item->fieldIdx)) {
1172 return NULL;
1173 }
1174 if (!dexDataMapVerify(state->pDataMap, item->annotationsOff,
1175 kDexTypeAnnotationSetItem)) {
1176 return NULL;
1177 }
1178 item++;
1179 }
1180
1181 return (const u1*) item;
1182}
1183
1184/* Helper for crossVerifyAnnotationsDirectoryItem(), which checks the
1185 * method elements. */
1186static const u1* crossVerifyMethodAnnotations(const CheckState* state,
1187 u4 count, const u1* addr, u4 definingClass) {
1188 const DexMethodAnnotationsItem* item = (DexMethodAnnotationsItem*) addr;
1189
1190 while (count--) {
1191 if (!verifyMethodDefiner(state, definingClass, item->methodIdx)) {
1192 return NULL;
1193 }
1194 if (!dexDataMapVerify(state->pDataMap, item->annotationsOff,
1195 kDexTypeAnnotationSetItem)) {
1196 return NULL;
1197 }
1198 item++;
1199 }
1200
1201 return (const u1*) item;
1202}
1203
1204/* Helper for crossVerifyAnnotationsDirectoryItem(), which checks the
1205 * parameter elements. */
1206static const u1* crossVerifyParameterAnnotations(const CheckState* state,
1207 u4 count, const u1* addr, u4 definingClass) {
1208 const DexParameterAnnotationsItem* item =
1209 (DexParameterAnnotationsItem*) addr;
1210
1211 while (count--) {
1212 if (!verifyMethodDefiner(state, definingClass, item->methodIdx)) {
1213 return NULL;
1214 }
1215 if (!dexDataMapVerify(state->pDataMap, item->annotationsOff,
1216 kDexTypeAnnotationSetRefList)) {
1217 return NULL;
1218 }
1219 item++;
1220 }
1221
1222 return (const u1*) item;
1223}
1224
1225/* Helper for crossVerifyClassDefItem() and
1226 * crossVerifyAnnotationsDirectoryItem(), which finds the type_idx of
1227 * the definer of the first item in the data. */
1228static u4 findFirstAnnotationsDirectoryDefiner(const CheckState* state,
1229 const DexAnnotationsDirectoryItem* dir) {
1230 if (dir->fieldsSize != 0) {
Dan Bornsteine02aff72010-01-26 12:58:08 -08001231 const DexFieldAnnotationsItem* fields =
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001232 dexGetFieldAnnotations(state->pDexFile, dir);
1233 const DexFieldId* field =
1234 dexGetFieldId(state->pDexFile, fields[0].fieldIdx);
1235 return field->classIdx;
1236 }
1237
1238 if (dir->methodsSize != 0) {
Dan Bornsteine02aff72010-01-26 12:58:08 -08001239 const DexMethodAnnotationsItem* methods =
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001240 dexGetMethodAnnotations(state->pDexFile, dir);
1241 const DexMethodId* method =
1242 dexGetMethodId(state->pDexFile, methods[0].methodIdx);
1243 return method->classIdx;
1244 }
1245
1246 if (dir->parametersSize != 0) {
Dan Bornsteine02aff72010-01-26 12:58:08 -08001247 const DexParameterAnnotationsItem* parameters =
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001248 dexGetParameterAnnotations(state->pDexFile, dir);
1249 const DexMethodId* method =
1250 dexGetMethodId(state->pDexFile, parameters[0].methodIdx);
1251 return method->classIdx;
1252 }
1253
1254 return kDexNoIndex;
1255}
1256
1257/* Perform cross-item verification of annotations_directory_item. */
1258static void* crossVerifyAnnotationsDirectoryItem(const CheckState* state,
1259 void* ptr) {
Dan Bornsteina70a3d82011-04-14 13:08:06 -07001260 const DexAnnotationsDirectoryItem* item = (const DexAnnotationsDirectoryItem*) ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001261 u4 definingClass = findFirstAnnotationsDirectoryDefiner(state, item);
1262
1263 if (!dexDataMapVerify0Ok(state->pDataMap,
1264 item->classAnnotationsOff, kDexTypeAnnotationSetItem)) {
1265 return NULL;
1266 }
1267
1268 const u1* addr = (const u1*) (item + 1);
1269
1270 if (item->fieldsSize != 0) {
1271 addr = crossVerifyFieldAnnotations(state, item->fieldsSize, addr,
1272 definingClass);
1273 if (addr == NULL) {
1274 return NULL;
1275 }
1276 }
1277
1278 if (item->methodsSize != 0) {
1279 addr = crossVerifyMethodAnnotations(state, item->methodsSize, addr,
1280 definingClass);
1281 if (addr == NULL) {
1282 return NULL;
1283 }
1284 }
1285
1286 if (item->parametersSize != 0) {
1287 addr = crossVerifyParameterAnnotations(state, item->parametersSize,
1288 addr, definingClass);
1289 if (addr == NULL) {
1290 return NULL;
1291 }
1292 }
1293
1294 return (void*) addr;
1295}
1296
1297/* Perform byte-swapping and intra-item verification on type_list. */
1298static void* swapTypeList(const CheckState* state, void* ptr)
1299{
Dan Bornsteina70a3d82011-04-14 13:08:06 -07001300 DexTypeList* pTypeList = (DexTypeList*) ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001301 DexTypeItem* pType;
1302 u4 count;
1303
1304 CHECK_PTR_RANGE(pTypeList, pTypeList + 1);
1305 SWAP_FIELD4(pTypeList->size);
1306 count = pTypeList->size;
1307 pType = pTypeList->list;
1308 CHECK_LIST_SIZE(pType, count, sizeof(DexTypeItem));
1309
1310 while (count--) {
1311 SWAP_INDEX2(pType->typeIdx, state->pHeader->typeIdsSize);
1312 pType++;
1313 }
1314
1315 return pType;
1316}
1317
1318/* Perform byte-swapping and intra-item verification on
1319 * annotation_set_ref_list. */
1320static void* swapAnnotationSetRefList(const CheckState* state, void* ptr) {
Dan Bornsteina70a3d82011-04-14 13:08:06 -07001321 DexAnnotationSetRefList* list = (DexAnnotationSetRefList*) ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001322 DexAnnotationSetRefItem* item;
1323 u4 count;
1324
1325 CHECK_PTR_RANGE(list, list + 1);
1326 SWAP_FIELD4(list->size);
1327 count = list->size;
1328 item = list->list;
1329 CHECK_LIST_SIZE(item, count, sizeof(DexAnnotationSetRefItem));
1330
1331 while (count--) {
1332 SWAP_OFFSET4(item->annotationsOff);
1333 item++;
1334 }
1335
1336 return item;
1337}
1338
1339/* Perform cross-item verification of annotation_set_ref_list. */
1340static void* crossVerifyAnnotationSetRefList(const CheckState* state,
1341 void* ptr) {
Dan Bornsteina70a3d82011-04-14 13:08:06 -07001342 const DexAnnotationSetRefList* list = (const DexAnnotationSetRefList*) ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001343 const DexAnnotationSetRefItem* item = list->list;
1344 int count = list->size;
1345
1346 while (count--) {
1347 if (!dexDataMapVerify0Ok(state->pDataMap,
1348 item->annotationsOff, kDexTypeAnnotationSetItem)) {
1349 return NULL;
1350 }
1351 item++;
1352 }
1353
1354 return (void*) item;
1355}
1356
1357/* Perform byte-swapping and intra-item verification on
1358 * annotation_set_item. */
1359static void* swapAnnotationSetItem(const CheckState* state, void* ptr) {
Dan Bornsteina70a3d82011-04-14 13:08:06 -07001360 DexAnnotationSetItem* set = (DexAnnotationSetItem*) ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001361 u4* item;
1362 u4 count;
1363
1364 CHECK_PTR_RANGE(set, set + 1);
1365 SWAP_FIELD4(set->size);
1366 count = set->size;
1367 item = set->entries;
1368 CHECK_LIST_SIZE(item, count, sizeof(u4));
1369
1370 while (count--) {
1371 SWAP_OFFSET4(*item);
1372 item++;
1373 }
1374
1375 return item;
1376}
1377
1378/* Helper for crossVerifyAnnotationSetItem(), which extracts the type_idx
1379 * out of an annotation_item. */
1380static u4 annotationItemTypeIdx(const DexAnnotationItem* item) {
1381 const u1* data = item->annotation;
1382 return readUnsignedLeb128(&data);
1383}
Dan Bornsteine02aff72010-01-26 12:58:08 -08001384
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001385/* Perform cross-item verification of annotation_set_item. */
1386static void* crossVerifyAnnotationSetItem(const CheckState* state, void* ptr) {
Dan Bornsteina70a3d82011-04-14 13:08:06 -07001387 const DexAnnotationSetItem* set = (const DexAnnotationSetItem*) ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001388 int count = set->size;
1389 u4 lastIdx = 0;
1390 bool first = true;
1391 int i;
1392
1393 for (i = 0; i < count; i++) {
1394 if (!dexDataMapVerify0Ok(state->pDataMap,
1395 dexGetAnnotationOff(set, i), kDexTypeAnnotationItem)) {
1396 return NULL;
1397 }
Dan Bornsteine02aff72010-01-26 12:58:08 -08001398
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001399 const DexAnnotationItem* annotation =
1400 dexGetAnnotationItem(state->pDexFile, set, i);
1401 u4 idx = annotationItemTypeIdx(annotation);
1402
1403 if (first) {
1404 first = false;
1405 } else if (lastIdx >= idx) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001406 ALOGE("Out-of-order entry types: %#x then %#x",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001407 lastIdx, idx);
1408 return NULL;
1409 }
1410
1411 lastIdx = idx;
1412 }
1413
1414 return (void*) (set->entries + count);
1415}
1416
1417/* Helper for verifyClassDataItem(), which checks a list of fields. */
1418static bool verifyFields(const CheckState* state, u4 size,
1419 DexField* fields, bool expectStatic) {
1420 u4 i;
1421
1422 for (i = 0; i < size; i++) {
1423 DexField* field = &fields[i];
1424 u4 accessFlags = field->accessFlags;
1425 bool isStatic = (accessFlags & ACC_STATIC) != 0;
1426
1427 CHECK_INDEX(field->fieldIdx, state->pHeader->fieldIdsSize);
1428
1429 if (isStatic != expectStatic) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001430 ALOGE("Field in wrong list @ %d", i);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001431 return false;
1432 }
1433
1434 if ((accessFlags & ~ACC_FIELD_MASK) != 0) {
Elliott Hughes4b44ea22013-08-02 15:41:00 -07001435 // The VM specification says that unknown flags should be ignored.
1436 ALOGV("Bogus field access flags %x @ %d", accessFlags, i);
1437 field->accessFlags &= ACC_FIELD_MASK;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001438 }
1439 }
1440
1441 return true;
1442}
1443
1444/* Helper for verifyClassDataItem(), which checks a list of methods. */
1445static bool verifyMethods(const CheckState* state, u4 size,
1446 DexMethod* methods, bool expectDirect) {
1447 u4 i;
1448
1449 for (i = 0; i < size; i++) {
1450 DexMethod* method = &methods[i];
1451
1452 CHECK_INDEX(method->methodIdx, state->pHeader->methodIdsSize);
1453
1454 u4 accessFlags = method->accessFlags;
1455 bool isDirect =
1456 (accessFlags & (ACC_STATIC | ACC_PRIVATE | ACC_CONSTRUCTOR)) != 0;
1457 bool expectCode = (accessFlags & (ACC_NATIVE | ACC_ABSTRACT)) == 0;
1458 bool isSynchronized = (accessFlags & ACC_SYNCHRONIZED) != 0;
1459 bool allowSynchronized = (accessFlags & ACC_NATIVE) != 0;
1460
1461 if (isDirect != expectDirect) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001462 ALOGE("Method in wrong list @ %d", i);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001463 return false;
1464 }
1465
Elliott Hughes4b44ea22013-08-02 15:41:00 -07001466 if (isSynchronized && !allowSynchronized) {
1467 ALOGE("Bogus method access flags (synchronization) %x @ %d", accessFlags, i);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001468 return false;
1469 }
1470
Elliott Hughes4b44ea22013-08-02 15:41:00 -07001471 if ((accessFlags & ~ACC_METHOD_MASK) != 0) {
1472 // The VM specification says that unknown flags should be ignored.
1473 ALOGV("Bogus method access flags %x @ %d", accessFlags, i);
1474 method->accessFlags &= ACC_METHOD_MASK;
1475 }
1476
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001477 if (expectCode) {
1478 if (method->codeOff == 0) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001479 ALOGE("Unexpected zero code_off for access_flags %x",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001480 accessFlags);
1481 return false;
1482 }
1483 } else if (method->codeOff != 0) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001484 ALOGE("Unexpected non-zero code_off %#x for access_flags %x",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001485 method->codeOff, accessFlags);
1486 return false;
1487 }
1488 }
1489
1490 return true;
1491}
1492
1493/* Helper for verifyClassDataItem(), which does most of the work. */
1494static bool verifyClassDataItem0(const CheckState* state,
1495 DexClassData* classData) {
1496 bool okay;
Dan Bornsteine02aff72010-01-26 12:58:08 -08001497
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001498 okay = verifyFields(state, classData->header.staticFieldsSize,
1499 classData->staticFields, true);
1500
1501 if (!okay) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001502 ALOGE("Trouble with static fields");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001503 return false;
1504 }
Dan Bornsteine02aff72010-01-26 12:58:08 -08001505
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001506 verifyFields(state, classData->header.instanceFieldsSize,
1507 classData->instanceFields, false);
1508
1509 if (!okay) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001510 ALOGE("Trouble with instance fields");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001511 return false;
1512 }
1513
1514 okay = verifyMethods(state, classData->header.directMethodsSize,
1515 classData->directMethods, true);
Dan Bornsteine02aff72010-01-26 12:58:08 -08001516
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001517 if (!okay) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001518 ALOGE("Trouble with direct methods");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001519 return false;
1520 }
1521
1522 okay = verifyMethods(state, classData->header.virtualMethodsSize,
1523 classData->virtualMethods, false);
Dan Bornsteine02aff72010-01-26 12:58:08 -08001524
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001525 if (!okay) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001526 ALOGE("Trouble with virtual methods");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001527 return false;
1528 }
1529
1530 return true;
1531}
1532
1533/* Perform intra-item verification on class_data_item. */
1534static void* intraVerifyClassDataItem(const CheckState* state, void* ptr) {
Dan Bornsteina70a3d82011-04-14 13:08:06 -07001535 const u1* data = (const u1*) ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001536 DexClassData* classData = dexReadAndVerifyClassData(&data, state->fileEnd);
1537
1538 if (classData == NULL) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001539 ALOGE("Unable to parse class_data_item");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001540 return NULL;
1541 }
1542
1543 bool okay = verifyClassDataItem0(state, classData);
1544
1545 free(classData);
1546
1547 if (!okay) {
1548 return NULL;
1549 }
Dan Bornsteine02aff72010-01-26 12:58:08 -08001550
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001551 return (void*) data;
1552}
1553
1554/* Helper for crossVerifyClassDefItem() and
1555 * crossVerifyClassDataItem(), which finds the type_idx of the definer
1556 * of the first item in the data. */
1557static u4 findFirstClassDataDefiner(const CheckState* state,
1558 DexClassData* classData) {
1559 if (classData->header.staticFieldsSize != 0) {
1560 u4 fieldIdx = classData->staticFields[0].fieldIdx;
1561 const DexFieldId* field = dexGetFieldId(state->pDexFile, fieldIdx);
1562 return field->classIdx;
1563 }
1564
1565 if (classData->header.instanceFieldsSize != 0) {
1566 u4 fieldIdx = classData->instanceFields[0].fieldIdx;
1567 const DexFieldId* field = dexGetFieldId(state->pDexFile, fieldIdx);
1568 return field->classIdx;
1569 }
1570
1571 if (classData->header.directMethodsSize != 0) {
1572 u4 methodIdx = classData->directMethods[0].methodIdx;
1573 const DexMethodId* meth = dexGetMethodId(state->pDexFile, methodIdx);
1574 return meth->classIdx;
1575 }
1576
1577 if (classData->header.virtualMethodsSize != 0) {
1578 u4 methodIdx = classData->virtualMethods[0].methodIdx;
1579 const DexMethodId* meth = dexGetMethodId(state->pDexFile, methodIdx);
1580 return meth->classIdx;
1581 }
1582
1583 return kDexNoIndex;
1584}
Dan Bornsteine02aff72010-01-26 12:58:08 -08001585
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001586/* Perform cross-item verification of class_data_item. */
1587static void* crossVerifyClassDataItem(const CheckState* state, void* ptr) {
Dan Bornsteina70a3d82011-04-14 13:08:06 -07001588 const u1* data = (const u1*) ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001589 DexClassData* classData = dexReadAndVerifyClassData(&data, state->fileEnd);
1590 u4 definingClass = findFirstClassDataDefiner(state, classData);
1591 bool okay = true;
1592 u4 i;
1593
1594 for (i = classData->header.staticFieldsSize; okay && (i > 0); /*i*/) {
1595 i--;
1596 const DexField* field = &classData->staticFields[i];
1597 okay = verifyFieldDefiner(state, definingClass, field->fieldIdx);
1598 }
1599
1600 for (i = classData->header.instanceFieldsSize; okay && (i > 0); /*i*/) {
1601 i--;
1602 const DexField* field = &classData->instanceFields[i];
1603 okay = verifyFieldDefiner(state, definingClass, field->fieldIdx);
1604 }
1605
1606 for (i = classData->header.directMethodsSize; okay && (i > 0); /*i*/) {
1607 i--;
1608 const DexMethod* meth = &classData->directMethods[i];
1609 okay = dexDataMapVerify0Ok(state->pDataMap, meth->codeOff,
1610 kDexTypeCodeItem)
1611 && verifyMethodDefiner(state, definingClass, meth->methodIdx);
1612 }
1613
1614 for (i = classData->header.virtualMethodsSize; okay && (i > 0); /*i*/) {
1615 i--;
1616 const DexMethod* meth = &classData->virtualMethods[i];
1617 okay = dexDataMapVerify0Ok(state->pDataMap, meth->codeOff,
1618 kDexTypeCodeItem)
1619 && verifyMethodDefiner(state, definingClass, meth->methodIdx);
1620 }
Dan Bornsteine02aff72010-01-26 12:58:08 -08001621
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001622 free(classData);
1623
1624 if (!okay) {
1625 return NULL;
1626 }
Dan Bornsteine02aff72010-01-26 12:58:08 -08001627
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001628 return (void*) data;
1629}
1630
1631/* Helper for swapCodeItem(), which fills an array with all the valid
1632 * handlerOff values for catch handlers and also verifies the handler
1633 * contents. */
1634static u4 setHandlerOffsAndVerify(const CheckState* state,
1635 DexCode* code, u4 firstOffset, u4 handlersSize, u4* handlerOffs) {
1636 const u1* fileEnd = state->fileEnd;
1637 const u1* handlersBase = dexGetCatchHandlerData(code);
1638 u4 offset = firstOffset;
1639 bool okay = true;
1640 u4 i;
1641
1642 for (i = 0; i < handlersSize; i++) {
1643 const u1* ptr = handlersBase + offset;
1644 int size = readAndVerifySignedLeb128(&ptr, fileEnd, &okay);
1645 bool catchAll;
1646
1647 if (!okay) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001648 ALOGE("Bogus size");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001649 return 0;
1650 }
1651
1652 if ((size < -65536) || (size > 65536)) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001653 ALOGE("Invalid size: %d", size);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001654 return 0;
1655 }
1656
1657 if (size <= 0) {
1658 catchAll = true;
1659 size = -size;
1660 } else {
1661 catchAll = false;
1662 }
Dan Bornsteine02aff72010-01-26 12:58:08 -08001663
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001664 handlerOffs[i] = offset;
1665
1666 while (size-- > 0) {
1667 u4 typeIdx =
1668 readAndVerifyUnsignedLeb128(&ptr, fileEnd, &okay);
1669
1670 if (!okay) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001671 ALOGE("Bogus type_idx");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001672 return 0;
1673 }
1674
1675 CHECK_INDEX(typeIdx, state->pHeader->typeIdsSize);
1676
1677 u4 addr = readAndVerifyUnsignedLeb128(&ptr, fileEnd, &okay);
1678
1679 if (!okay) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001680 ALOGE("Bogus addr");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001681 return 0;
1682 }
1683
1684 if (addr >= code->insnsSize) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001685 ALOGE("Invalid addr: %#x", addr);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001686 return 0;
1687 }
1688 }
1689
1690 if (catchAll) {
1691 u4 addr = readAndVerifyUnsignedLeb128(&ptr, fileEnd, &okay);
1692
1693 if (!okay) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001694 ALOGE("Bogus catch_all_addr");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001695 return 0;
1696 }
1697
1698 if (addr >= code->insnsSize) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001699 ALOGE("Invalid catch_all_addr: %#x", addr);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001700 return 0;
1701 }
1702 }
1703
1704 offset = ptr - handlersBase;
1705 }
1706
1707 return offset;
1708}
1709
1710/* Helper for swapCodeItem(), which does all the try-catch related
1711 * swapping and verification. */
1712static void* swapTriesAndCatches(const CheckState* state, DexCode* code) {
1713 const u1* encodedHandlers = dexGetCatchHandlerData(code);
1714 const u1* encodedPtr = encodedHandlers;
1715 bool okay = true;
1716 u4 handlersSize =
1717 readAndVerifyUnsignedLeb128(&encodedPtr, state->fileEnd, &okay);
1718
1719 if (!okay) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001720 ALOGE("Bogus handlers_size");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001721 return NULL;
1722 }
1723
1724 if ((handlersSize == 0) || (handlersSize >= 65536)) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001725 ALOGE("Invalid handlers_size: %d", handlersSize);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001726 return NULL;
1727 }
Dan Bornsteine02aff72010-01-26 12:58:08 -08001728
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001729 u4 handlerOffs[handlersSize]; // list of valid handlerOff values
Dan Bornsteine02aff72010-01-26 12:58:08 -08001730 u4 endOffset = setHandlerOffsAndVerify(state, code,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001731 encodedPtr - encodedHandlers,
1732 handlersSize, handlerOffs);
1733
1734 if (endOffset == 0) {
1735 return NULL;
1736 }
1737
1738 DexTry* tries = (DexTry*) dexGetTries(code);
1739 u4 count = code->triesSize;
1740 u4 lastEnd = 0;
1741
1742 CHECK_LIST_SIZE(tries, count, sizeof(DexTry));
1743
1744 while (count--) {
1745 u4 i;
1746
1747 SWAP_FIELD4(tries->startAddr);
1748 SWAP_FIELD2(tries->insnCount);
1749 SWAP_FIELD2(tries->handlerOff);
1750
1751 if (tries->startAddr < lastEnd) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001752 ALOGE("Out-of-order try");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001753 return NULL;
1754 }
1755
1756 if (tries->startAddr >= code->insnsSize) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001757 ALOGE("Invalid start_addr: %#x", tries->startAddr);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001758 return NULL;
1759 }
1760
1761 for (i = 0; i < handlersSize; i++) {
1762 if (tries->handlerOff == handlerOffs[i]) {
1763 break;
1764 }
1765 }
1766
1767 if (i == handlersSize) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001768 ALOGE("Bogus handler offset: %#x", tries->handlerOff);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001769 return NULL;
1770 }
1771
1772 lastEnd = tries->startAddr + tries->insnCount;
1773
1774 if (lastEnd > code->insnsSize) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001775 ALOGE("Invalid insn_count: %#x (end addr %#x)",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001776 tries->insnCount, lastEnd);
1777 return NULL;
1778 }
Dan Bornsteine02aff72010-01-26 12:58:08 -08001779
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001780 tries++;
1781 }
1782
1783 return (u1*) encodedHandlers + endOffset;
1784}
1785
1786/* Perform byte-swapping and intra-item verification on code_item. */
1787static void* swapCodeItem(const CheckState* state, void* ptr) {
Dan Bornsteina70a3d82011-04-14 13:08:06 -07001788 DexCode* item = (DexCode*) ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001789 u2* insns;
1790 u4 count;
1791
1792 CHECK_PTR_RANGE(item, item + 1);
1793 SWAP_FIELD2(item->registersSize);
1794 SWAP_FIELD2(item->insSize);
1795 SWAP_FIELD2(item->outsSize);
1796 SWAP_FIELD2(item->triesSize);
1797 SWAP_OFFSET4(item->debugInfoOff);
1798 SWAP_FIELD4(item->insnsSize);
1799
Brian Carlstromfbdcfb92010-05-28 15:42:12 -07001800 if (item->insSize > item->registersSize) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001801 ALOGE("insSize (%u) > registersSize (%u)", item->insSize,
Brian Carlstromfbdcfb92010-05-28 15:42:12 -07001802 item->registersSize);
1803 return NULL;
1804 }
1805
1806 if ((item->outsSize > 5) && (item->outsSize > item->registersSize)) {
1807 /*
1808 * It's okay for outsSize to be up to five, even if registersSize
1809 * is smaller, since the short forms of method invocation allow
1810 * repetition of a register multiple times within a single parameter
1811 * list. Longer parameter lists, though, need to be represented
1812 * in-order in the register file.
1813 */
Steve Blockc1a4ab92012-01-06 19:16:58 +00001814 ALOGE("outsSize (%u) > registersSize (%u)", item->outsSize,
Brian Carlstromfbdcfb92010-05-28 15:42:12 -07001815 item->registersSize);
1816 return NULL;
1817 }
1818
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001819 count = item->insnsSize;
1820 insns = item->insns;
1821 CHECK_LIST_SIZE(insns, count, sizeof(u2));
1822
1823 while (count--) {
1824 *insns = SWAP2(*insns);
1825 insns++;
1826 }
1827
1828 if (item->triesSize == 0) {
1829 ptr = insns;
1830 } else {
SangWook Hanb210a9f2012-07-15 22:42:28 +09001831 if ((((uintptr_t) insns) & 3) != 0) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001832 // Four-byte alignment for the tries. Verify the spacer is a 0.
1833 if (*insns != 0) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001834 ALOGE("Non-zero padding: %#x", (u4) *insns);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001835 return NULL;
1836 }
1837 }
1838
1839 ptr = swapTriesAndCatches(state, item);
1840 }
1841
1842 return ptr;
1843}
1844
1845/* Perform intra-item verification on string_data_item. */
1846static void* intraVerifyStringDataItem(const CheckState* state, void* ptr) {
1847 const u1* fileEnd = state->fileEnd;
Dan Bornsteina70a3d82011-04-14 13:08:06 -07001848 const u1* data = (const u1*) ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001849 bool okay = true;
1850 u4 utf16Size = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
1851 u4 i;
1852
1853 if (!okay) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001854 ALOGE("Bogus utf16_size");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001855 return NULL;
1856 }
1857
1858 for (i = 0; i < utf16Size; i++) {
1859 if (data >= fileEnd) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001860 ALOGE("String data would go beyond end-of-file");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001861 return NULL;
1862 }
Dan Bornsteine02aff72010-01-26 12:58:08 -08001863
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001864 u1 byte1 = *(data++);
1865
1866 // Switch on the high four bits.
1867 switch (byte1 >> 4) {
1868 case 0x00: {
1869 // Special case of bit pattern 0xxx.
1870 if (byte1 == 0) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001871 ALOGE("String shorter than indicated utf16_size %#x",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001872 utf16Size);
1873 return NULL;
1874 }
1875 break;
1876 }
1877 case 0x01:
1878 case 0x02:
1879 case 0x03:
1880 case 0x04:
1881 case 0x05:
1882 case 0x06:
1883 case 0x07: {
1884 // Bit pattern 0xxx. No need for any extra bytes or checks.
1885 break;
1886 }
1887 case 0x08:
1888 case 0x09:
1889 case 0x0a:
1890 case 0x0b:
1891 case 0x0f: {
1892 /*
1893 * Bit pattern 10xx or 1111, which are illegal start bytes.
1894 * Note: 1111 is valid for normal UTF-8, but not the
1895 * modified UTF-8 used here.
1896 */
Steve Blockc1a4ab92012-01-06 19:16:58 +00001897 ALOGE("Illegal start byte %#x", byte1);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001898 return NULL;
1899 }
1900 case 0x0e: {
1901 // Bit pattern 1110, so there are two additional bytes.
1902 u1 byte2 = *(data++);
1903 if ((byte2 & 0xc0) != 0x80) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001904 ALOGE("Illegal continuation byte %#x", byte2);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001905 return NULL;
1906 }
1907 u1 byte3 = *(data++);
1908 if ((byte3 & 0xc0) != 0x80) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001909 ALOGE("Illegal continuation byte %#x", byte3);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001910 return NULL;
1911 }
1912 u2 value = ((byte1 & 0x0f) << 12) | ((byte2 & 0x3f) << 6)
1913 | (byte3 & 0x3f);
1914 if (value < 0x800) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001915 ALOGE("Illegal representation for value %x", value);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001916 return NULL;
1917 }
1918 break;
1919 }
1920 case 0x0c:
1921 case 0x0d: {
1922 // Bit pattern 110x, so there is one additional byte.
1923 u1 byte2 = *(data++);
1924 if ((byte2 & 0xc0) != 0x80) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001925 ALOGE("Illegal continuation byte %#x", byte2);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001926 return NULL;
1927 }
1928 u2 value = ((byte1 & 0x1f) << 6) | (byte2 & 0x3f);
1929 if ((value != 0) && (value < 0x80)) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001930 ALOGE("Illegal representation for value %x", value);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001931 return NULL;
1932 }
1933 break;
1934 }
1935 }
1936 }
1937
1938 if (*(data++) != '\0') {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001939 ALOGE("String longer than indicated utf16_size %#x", utf16Size);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001940 return NULL;
1941 }
1942
1943 return (void*) data;
1944}
1945
1946/* Perform intra-item verification on debug_info_item. */
1947static void* intraVerifyDebugInfoItem(const CheckState* state, void* ptr) {
1948 const u1* fileEnd = state->fileEnd;
Dan Bornsteina70a3d82011-04-14 13:08:06 -07001949 const u1* data = (const u1*) ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001950 bool okay = true;
1951 u4 i;
1952
1953 readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
1954
1955 if (!okay) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001956 ALOGE("Bogus line_start");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001957 return NULL;
1958 }
1959
1960 u4 parametersSize =
1961 readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
1962
1963 if (!okay) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001964 ALOGE("Bogus parameters_size");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001965 return NULL;
1966 }
1967
1968 if (parametersSize > 65536) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001969 ALOGE("Invalid parameters_size: %#x", parametersSize);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001970 return NULL;
1971 }
1972
1973 for (i = 0; i < parametersSize; i++) {
1974 u4 parameterName =
1975 readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
1976
1977 if (!okay) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00001978 ALOGE("Bogus parameter_name");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08001979 return NULL;
1980 }
1981
1982 if (parameterName != 0) {
1983 parameterName--;
1984 CHECK_INDEX(parameterName, state->pHeader->stringIdsSize);
1985 }
1986 }
1987
1988 bool done = false;
1989 while (!done) {
1990 u1 opcode = *(data++);
1991
1992 switch (opcode) {
1993 case DBG_END_SEQUENCE: {
1994 done = true;
1995 break;
1996 }
1997 case DBG_ADVANCE_PC: {
1998 readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
1999 break;
2000 }
2001 case DBG_ADVANCE_LINE: {
2002 readAndVerifySignedLeb128(&data, fileEnd, &okay);
2003 break;
2004 }
2005 case DBG_START_LOCAL: {
2006 u4 idx;
2007 u4 regNum = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2008 if (!okay) break;
2009 if (regNum >= 65536) {
2010 okay = false;
2011 break;
2012 }
2013 idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2014 if (!okay) break;
2015 if (idx != 0) {
2016 idx--;
2017 CHECK_INDEX(idx, state->pHeader->stringIdsSize);
2018 }
2019 idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2020 if (!okay) break;
2021 if (idx != 0) {
2022 idx--;
2023 CHECK_INDEX(idx, state->pHeader->stringIdsSize);
2024 }
2025 break;
2026 }
2027 case DBG_END_LOCAL:
2028 case DBG_RESTART_LOCAL: {
2029 u4 regNum = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2030 if (!okay) break;
2031 if (regNum >= 65536) {
2032 okay = false;
2033 break;
2034 }
2035 break;
2036 }
2037 case DBG_START_LOCAL_EXTENDED: {
2038 u4 idx;
2039 u4 regNum = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2040 if (!okay) break;
2041 if (regNum >= 65536) {
2042 okay = false;
2043 break;
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 idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2052 if (!okay) break;
2053 if (idx != 0) {
2054 idx--;
2055 CHECK_INDEX(idx, state->pHeader->stringIdsSize);
2056 }
2057 idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2058 if (!okay) break;
2059 if (idx != 0) {
2060 idx--;
2061 CHECK_INDEX(idx, state->pHeader->stringIdsSize);
2062 }
2063 break;
2064 }
2065 case DBG_SET_FILE: {
2066 u4 idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2067 if (!okay) break;
2068 if (idx != 0) {
2069 idx--;
2070 CHECK_INDEX(idx, state->pHeader->stringIdsSize);
2071 }
2072 break;
2073 }
2074 default: {
2075 // No arguments to parse for anything else.
2076 }
2077 }
2078
2079 if (!okay) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002080 ALOGE("Bogus syntax for opcode %02x", opcode);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002081 return NULL;
2082 }
2083 }
Dan Bornsteine02aff72010-01-26 12:58:08 -08002084
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002085 return (void*) data;
2086}
2087
2088/* defined below */
2089static const u1* verifyEncodedValue(const CheckState* state, const u1* data,
2090 bool crossVerify);
2091static const u1* verifyEncodedAnnotation(const CheckState* state,
2092 const u1* data, bool crossVerify);
2093
2094/* Helper for verifyEncodedValue(), which reads a 1- to 4- byte unsigned
2095 * little endian value. */
2096static u4 readUnsignedLittleEndian(const CheckState* state, const u1** pData,
2097 u4 size) {
2098 const u1* data = *pData;
2099 u4 result = 0;
2100 u4 i;
2101
2102 CHECK_PTR_RANGE(data, data + size);
Dan Bornsteine02aff72010-01-26 12:58:08 -08002103
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002104 for (i = 0; i < size; i++) {
2105 result |= ((u4) *(data++)) << (i * 8);
2106 }
2107
2108 *pData = data;
Dan Bornsteine02aff72010-01-26 12:58:08 -08002109 return result;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002110}
2111
2112/* Helper for *VerifyAnnotationItem() and *VerifyEncodedArrayItem(), which
2113 * verifies an encoded_array. */
2114static const u1* verifyEncodedArray(const CheckState* state,
2115 const u1* data, bool crossVerify) {
2116 bool okay = true;
2117 u4 size = readAndVerifyUnsignedLeb128(&data, state->fileEnd, &okay);
2118
2119 if (!okay) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002120 ALOGE("Bogus encoded_array size");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002121 return NULL;
2122 }
2123
2124 while (size--) {
2125 data = verifyEncodedValue(state, data, crossVerify);
2126 if (data == NULL) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002127 ALOGE("Bogus encoded_array value");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002128 return NULL;
2129 }
2130 }
2131
2132 return data;
2133}
2134
2135/* Helper for *VerifyAnnotationItem() and *VerifyEncodedArrayItem(), which
2136 * verifies an encoded_value. */
2137static const u1* verifyEncodedValue(const CheckState* state,
2138 const u1* data, bool crossVerify) {
2139 CHECK_PTR_RANGE(data, data + 1);
Dan Bornsteine02aff72010-01-26 12:58:08 -08002140
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002141 u1 headerByte = *(data++);
2142 u4 valueType = headerByte & kDexAnnotationValueTypeMask;
2143 u4 valueArg = headerByte >> kDexAnnotationValueArgShift;
2144
2145 switch (valueType) {
2146 case kDexAnnotationByte: {
2147 if (valueArg != 0) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002148 ALOGE("Bogus byte size %#x", valueArg);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002149 return NULL;
2150 }
2151 data++;
2152 break;
2153 }
2154 case kDexAnnotationShort:
2155 case kDexAnnotationChar: {
2156 if (valueArg > 1) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002157 ALOGE("Bogus char/short size %#x", valueArg);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002158 return NULL;
2159 }
2160 data += valueArg + 1;
2161 break;
2162 }
2163 case kDexAnnotationInt:
2164 case kDexAnnotationFloat: {
2165 if (valueArg > 3) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002166 ALOGE("Bogus int/float size %#x", valueArg);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002167 return NULL;
2168 }
2169 data += valueArg + 1;
2170 break;
2171 }
2172 case kDexAnnotationLong:
2173 case kDexAnnotationDouble: {
2174 data += valueArg + 1;
2175 break;
2176 }
2177 case kDexAnnotationString: {
2178 if (valueArg > 3) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002179 ALOGE("Bogus string size %#x", valueArg);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002180 return NULL;
2181 }
2182 u4 idx = readUnsignedLittleEndian(state, &data, valueArg + 1);
2183 CHECK_INDEX(idx, state->pHeader->stringIdsSize);
2184 break;
2185 }
2186 case kDexAnnotationType: {
2187 if (valueArg > 3) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002188 ALOGE("Bogus type size %#x", valueArg);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002189 return NULL;
2190 }
2191 u4 idx = readUnsignedLittleEndian(state, &data, valueArg + 1);
2192 CHECK_INDEX(idx, state->pHeader->typeIdsSize);
2193 break;
2194 }
2195 case kDexAnnotationField:
2196 case kDexAnnotationEnum: {
2197 if (valueArg > 3) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002198 ALOGE("Bogus field/enum size %#x", valueArg);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002199 return NULL;
2200 }
2201 u4 idx = readUnsignedLittleEndian(state, &data, valueArg + 1);
2202 CHECK_INDEX(idx, state->pHeader->fieldIdsSize);
2203 break;
2204 }
2205 case kDexAnnotationMethod: {
2206 if (valueArg > 3) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002207 ALOGE("Bogus method size %#x", valueArg);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002208 return NULL;
2209 }
2210 u4 idx = readUnsignedLittleEndian(state, &data, valueArg + 1);
2211 CHECK_INDEX(idx, state->pHeader->methodIdsSize);
2212 break;
2213 }
2214 case kDexAnnotationArray: {
2215 if (valueArg != 0) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002216 ALOGE("Bogus array value_arg %#x", valueArg);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002217 return NULL;
2218 }
2219 data = verifyEncodedArray(state, data, crossVerify);
2220 break;
2221 }
2222 case kDexAnnotationAnnotation: {
2223 if (valueArg != 0) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002224 ALOGE("Bogus annotation value_arg %#x", valueArg);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002225 return NULL;
2226 }
2227 data = verifyEncodedAnnotation(state, data, crossVerify);
2228 break;
2229 }
2230 case kDexAnnotationNull: {
2231 if (valueArg != 0) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002232 ALOGE("Bogus null value_arg %#x", valueArg);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002233 return NULL;
2234 }
2235 // Nothing else to do for this type.
2236 break;
2237 }
2238 case kDexAnnotationBoolean: {
2239 if (valueArg > 1) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002240 ALOGE("Bogus boolean value_arg %#x", valueArg);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002241 return NULL;
2242 }
2243 // Nothing else to do for this type.
2244 break;
2245 }
2246 default: {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002247 ALOGE("Bogus value_type %#x", valueType);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002248 return NULL;
2249 }
2250 }
2251
2252 return data;
2253}
2254
2255/* Helper for *VerifyAnnotationItem() and *VerifyEncodedArrayItem(), which
2256 * verifies an encoded_annotation. */
2257static const u1* verifyEncodedAnnotation(const CheckState* state,
2258 const u1* data, bool crossVerify) {
2259 const u1* fileEnd = state->fileEnd;
2260 bool okay = true;
2261 u4 idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2262
2263 if (!okay) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002264 ALOGE("Bogus encoded_annotation type_idx");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002265 return NULL;
2266 }
2267
2268 CHECK_INDEX(idx, state->pHeader->typeIdsSize);
2269
2270 if (crossVerify) {
2271 const char* descriptor = dexStringByTypeIdx(state->pDexFile, idx);
2272 if (!dexIsClassDescriptor(descriptor)) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002273 ALOGE("Bogus annotation type: '%s'", descriptor);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002274 return NULL;
2275 }
2276 }
Dan Bornsteine02aff72010-01-26 12:58:08 -08002277
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002278 u4 size = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
2279 u4 lastIdx = 0;
2280 bool first = true;
2281
2282 if (!okay) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002283 ALOGE("Bogus encoded_annotation size");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002284 return NULL;
2285 }
2286
2287 while (size--) {
2288 idx = readAndVerifyUnsignedLeb128(&data, fileEnd, &okay);
Dan Bornsteine02aff72010-01-26 12:58:08 -08002289
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002290 if (!okay) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002291 ALOGE("Bogus encoded_annotation name_idx");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002292 return NULL;
2293 }
2294
2295 CHECK_INDEX(idx, state->pHeader->stringIdsSize);
2296
2297 if (crossVerify) {
2298 const char* name = dexStringById(state->pDexFile, idx);
2299 if (!dexIsValidMemberName(name)) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002300 ALOGE("Bogus annotation member name: '%s'", name);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002301 return NULL;
2302 }
2303 }
2304
2305 if (first) {
2306 first = false;
2307 } else if (lastIdx >= idx) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002308 ALOGE("Out-of-order encoded_annotation name_idx: %#x then %#x",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002309 lastIdx, idx);
2310 return NULL;
2311 }
2312
2313 data = verifyEncodedValue(state, data, crossVerify);
2314 lastIdx = idx;
2315
2316 if (data == NULL) {
2317 return NULL;
2318 }
2319 }
2320
2321 return data;
2322}
2323
2324/* Perform intra-item verification on encoded_array_item. */
2325static void* intraVerifyEncodedArrayItem(const CheckState* state, void* ptr) {
2326 return (void*) verifyEncodedArray(state, (const u1*) ptr, false);
2327}
2328
2329/* Perform intra-item verification on annotation_item. */
2330static void* intraVerifyAnnotationItem(const CheckState* state, void* ptr) {
Dan Bornsteina70a3d82011-04-14 13:08:06 -07002331 const u1* data = (const u1*) ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002332
2333 CHECK_PTR_RANGE(data, data + 1);
Dan Bornsteine02aff72010-01-26 12:58:08 -08002334
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002335 switch (*(data++)) {
2336 case kDexVisibilityBuild:
2337 case kDexVisibilityRuntime:
2338 case kDexVisibilitySystem: {
2339 break;
2340 }
2341 default: {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002342 ALOGE("Bogus annotation visibility: %#x", *data);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002343 return NULL;
2344 }
2345 }
2346
2347 return (void*) verifyEncodedAnnotation(state, data, false);
2348}
2349
2350/* Perform cross-item verification on annotation_item. */
2351static void* crossVerifyAnnotationItem(const CheckState* state, void* ptr) {
Dan Bornsteina70a3d82011-04-14 13:08:06 -07002352 const u1* data = (const u1*) ptr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002353
2354 // Skip the visibility byte.
2355 data++;
2356
2357 return (void*) verifyEncodedAnnotation(state, data, true);
2358}
2359
2360
2361
2362
2363/*
2364 * Function to visit an individual top-level item type.
2365 */
2366typedef void* ItemVisitorFunction(const CheckState* state, void* ptr);
2367
2368/*
2369 * Iterate over all the items in a section, optionally updating the
2370 * data map (done if mapType is passed as non-negative). The section
2371 * must consist of concatenated items of the same type.
2372 */
2373static bool iterateSectionWithOptionalUpdate(CheckState* state,
2374 u4 offset, u4 count, ItemVisitorFunction* func, u4 alignment,
2375 u4* nextOffset, int mapType) {
2376 u4 alignmentMask = alignment - 1;
2377 u4 i;
2378
2379 state->previousItem = NULL;
Dan Bornsteine02aff72010-01-26 12:58:08 -08002380
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002381 for (i = 0; i < count; i++) {
2382 u4 newOffset = (offset + alignmentMask) & ~alignmentMask;
Dan Bornsteina70a3d82011-04-14 13:08:06 -07002383 u1* ptr = (u1*) filePointer(state, newOffset);
Dan Bornsteine02aff72010-01-26 12:58:08 -08002384
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002385 if (offset < newOffset) {
Dan Bornsteina70a3d82011-04-14 13:08:06 -07002386 ptr = (u1*) filePointer(state, offset);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002387 if (offset < newOffset) {
2388 CHECK_OFFSET_RANGE(offset, newOffset);
2389 while (offset < newOffset) {
2390 if (*ptr != '\0') {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002391 ALOGE("Non-zero padding 0x%02x @ %x", *ptr, offset);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002392 return false;
2393 }
2394 ptr++;
2395 offset++;
2396 }
2397 }
2398 }
2399
2400 u1* newPtr = (u1*) func(state, ptr);
2401 newOffset = fileOffset(state, newPtr);
2402
2403 if (newPtr == NULL) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002404 ALOGE("Trouble with item %d @ offset %#x", i, offset);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002405 return false;
2406 }
2407
2408 if (newOffset > state->fileLen) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002409 ALOGE("Item %d @ offset %#x ends out of bounds", i, offset);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002410 return false;
2411 }
2412
2413 if (mapType >= 0) {
2414 dexDataMapAdd(state->pDataMap, offset, mapType);
2415 }
2416
2417 state->previousItem = ptr;
2418 offset = newOffset;
2419 }
2420
2421 if (nextOffset != NULL) {
2422 *nextOffset = offset;
2423 }
2424
2425 return true;
2426}
2427
2428/*
2429 * Iterate over all the items in a section. The section must consist of
2430 * concatenated items of the same type. This variant will not update the data
2431 * map.
2432 */
2433static bool iterateSection(CheckState* state, u4 offset, u4 count,
2434 ItemVisitorFunction* func, u4 alignment, u4* nextOffset) {
2435 return iterateSectionWithOptionalUpdate(state, offset, count, func,
2436 alignment, nextOffset, -1);
2437}
2438
2439/*
2440 * Like iterateSection(), but also check that the offset and count match
2441 * a given pair of expected values.
2442 */
2443static bool checkBoundsAndIterateSection(CheckState* state,
2444 u4 offset, u4 count, u4 expectedOffset, u4 expectedCount,
2445 ItemVisitorFunction* func, u4 alignment, u4* nextOffset) {
2446 if (offset != expectedOffset) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002447 ALOGE("Bogus offset for section: got %#x; expected %#x",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002448 offset, expectedOffset);
2449 return false;
2450 }
2451
2452 if (count != expectedCount) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002453 ALOGE("Bogus size for section: got %#x; expected %#x",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002454 count, expectedCount);
2455 return false;
2456 }
2457
2458 return iterateSection(state, offset, count, func, alignment, nextOffset);
2459}
2460
2461/*
2462 * Like iterateSection(), but also update the data section map and
2463 * check that all the items fall within the data section.
2464 */
2465static bool iterateDataSection(CheckState* state, u4 offset, u4 count,
2466 ItemVisitorFunction* func, u4 alignment, u4* nextOffset, int mapType) {
2467 u4 dataStart = state->pHeader->dataOff;
2468 u4 dataEnd = dataStart + state->pHeader->dataSize;
2469
2470 assert(nextOffset != NULL);
2471
2472 if ((offset < dataStart) || (offset >= dataEnd)) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002473 ALOGE("Bogus offset for data subsection: %#x", offset);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002474 return false;
2475 }
2476
2477 if (!iterateSectionWithOptionalUpdate(state, offset, count, func,
2478 alignment, nextOffset, mapType)) {
2479 return false;
2480 }
2481
2482 if (*nextOffset > dataEnd) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002483 ALOGE("Out-of-bounds end of data subsection: %#x", *nextOffset);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002484 return false;
2485 }
2486
2487 return true;
2488}
2489
2490/*
2491 * Byte-swap all items in the given map except the header and the map
2492 * itself, both of which should have already gotten swapped. This also
2493 * does all possible intra-item verification, that is, verification
2494 * that doesn't need to assume the sanctity of the contents of *other*
2495 * items. The intra-item limitation is because at the time an item is
2496 * asked to verify itself, it can't assume that the items it refers to
2497 * have been byte-swapped and verified.
2498 */
2499static bool swapEverythingButHeaderAndMap(CheckState* state,
2500 DexMapList* pMap) {
2501 const DexMapItem* item = pMap->list;
2502 u4 lastOffset = 0;
2503 u4 count = pMap->size;
2504 bool okay = true;
2505
2506 while (okay && count--) {
2507 u4 sectionOffset = item->offset;
2508 u4 sectionCount = item->size;
2509 u2 type = item->type;
2510
2511 if (lastOffset < sectionOffset) {
2512 CHECK_OFFSET_RANGE(lastOffset, sectionOffset);
Dan Bornsteina70a3d82011-04-14 13:08:06 -07002513 const u1* ptr = (const u1*) filePointer(state, lastOffset);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002514 while (lastOffset < sectionOffset) {
2515 if (*ptr != '\0') {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002516 ALOGE("Non-zero padding 0x%02x before section start @ %x",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002517 *ptr, lastOffset);
2518 okay = false;
2519 break;
2520 }
2521 ptr++;
2522 lastOffset++;
2523 }
2524 } else if (lastOffset > sectionOffset) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002525 ALOGE("Section overlap or out-of-order map: %x, %x",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002526 lastOffset, sectionOffset);
2527 okay = false;
2528 }
2529
2530 if (!okay) {
2531 break;
2532 }
2533
2534 switch (type) {
2535 case kDexTypeHeaderItem: {
2536 /*
2537 * The header got swapped very early on, but do some
2538 * additional sanity checking here.
2539 */
2540 okay = checkHeaderSection(state, sectionOffset, sectionCount,
2541 &lastOffset);
2542 break;
2543 }
2544 case kDexTypeStringIdItem: {
2545 okay = checkBoundsAndIterateSection(state, sectionOffset,
2546 sectionCount, state->pHeader->stringIdsOff,
2547 state->pHeader->stringIdsSize, swapStringIdItem,
2548 sizeof(u4), &lastOffset);
2549 break;
2550 }
2551 case kDexTypeTypeIdItem: {
2552 okay = checkBoundsAndIterateSection(state, sectionOffset,
2553 sectionCount, state->pHeader->typeIdsOff,
2554 state->pHeader->typeIdsSize, swapTypeIdItem,
2555 sizeof(u4), &lastOffset);
2556 break;
2557 }
2558 case kDexTypeProtoIdItem: {
2559 okay = checkBoundsAndIterateSection(state, sectionOffset,
2560 sectionCount, state->pHeader->protoIdsOff,
2561 state->pHeader->protoIdsSize, swapProtoIdItem,
2562 sizeof(u4), &lastOffset);
2563 break;
2564 }
2565 case kDexTypeFieldIdItem: {
2566 okay = checkBoundsAndIterateSection(state, sectionOffset,
2567 sectionCount, state->pHeader->fieldIdsOff,
2568 state->pHeader->fieldIdsSize, swapFieldIdItem,
2569 sizeof(u4), &lastOffset);
2570 break;
2571 }
2572 case kDexTypeMethodIdItem: {
2573 okay = checkBoundsAndIterateSection(state, sectionOffset,
2574 sectionCount, state->pHeader->methodIdsOff,
2575 state->pHeader->methodIdsSize, swapMethodIdItem,
2576 sizeof(u4), &lastOffset);
2577 break;
2578 }
2579 case kDexTypeClassDefItem: {
2580 okay = checkBoundsAndIterateSection(state, sectionOffset,
2581 sectionCount, state->pHeader->classDefsOff,
2582 state->pHeader->classDefsSize, swapClassDefItem,
2583 sizeof(u4), &lastOffset);
2584 break;
2585 }
2586 case kDexTypeMapList: {
Dan Bornsteine02aff72010-01-26 12:58:08 -08002587 /*
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002588 * The map section was swapped early on, but do some
2589 * additional sanity checking here.
2590 */
2591 okay = checkMapSection(state, sectionOffset, sectionCount,
2592 &lastOffset);
2593 break;
2594 }
2595 case kDexTypeTypeList: {
2596 okay = iterateDataSection(state, sectionOffset, sectionCount,
2597 swapTypeList, sizeof(u4), &lastOffset, type);
2598 break;
2599 }
2600 case kDexTypeAnnotationSetRefList: {
2601 okay = iterateDataSection(state, sectionOffset, sectionCount,
2602 swapAnnotationSetRefList, sizeof(u4), &lastOffset,
2603 type);
2604 break;
2605 }
2606 case kDexTypeAnnotationSetItem: {
2607 okay = iterateDataSection(state, sectionOffset, sectionCount,
2608 swapAnnotationSetItem, sizeof(u4), &lastOffset, type);
2609 break;
2610 }
2611 case kDexTypeClassDataItem: {
2612 okay = iterateDataSection(state, sectionOffset, sectionCount,
2613 intraVerifyClassDataItem, sizeof(u1), &lastOffset,
2614 type);
2615 break;
2616 }
2617 case kDexTypeCodeItem: {
2618 okay = iterateDataSection(state, sectionOffset, sectionCount,
2619 swapCodeItem, sizeof(u4), &lastOffset, type);
2620 break;
2621 }
2622 case kDexTypeStringDataItem: {
2623 okay = iterateDataSection(state, sectionOffset, sectionCount,
2624 intraVerifyStringDataItem, sizeof(u1), &lastOffset,
2625 type);
2626 break;
2627 }
2628 case kDexTypeDebugInfoItem: {
2629 okay = iterateDataSection(state, sectionOffset, sectionCount,
2630 intraVerifyDebugInfoItem, sizeof(u1), &lastOffset,
2631 type);
2632 break;
2633 }
2634 case kDexTypeAnnotationItem: {
2635 okay = iterateDataSection(state, sectionOffset, sectionCount,
2636 intraVerifyAnnotationItem, sizeof(u1), &lastOffset,
2637 type);
2638 break;
2639 }
2640 case kDexTypeEncodedArrayItem: {
2641 okay = iterateDataSection(state, sectionOffset, sectionCount,
2642 intraVerifyEncodedArrayItem, sizeof(u1), &lastOffset,
2643 type);
2644 break;
2645 }
2646 case kDexTypeAnnotationsDirectoryItem: {
2647 okay = iterateDataSection(state, sectionOffset, sectionCount,
2648 swapAnnotationsDirectoryItem, sizeof(u4), &lastOffset,
2649 type);
2650 break;
2651 }
2652 default: {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002653 ALOGE("Unknown map item type %04x", type);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002654 return false;
2655 }
2656 }
2657
2658 if (!okay) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002659 ALOGE("Swap of section type %04x failed", type);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002660 }
2661
2662 item++;
2663 }
2664
2665 return okay;
2666}
2667
2668/*
2669 * Perform cross-item verification on everything that needs it. This
2670 * pass is only called after all items are byte-swapped and
2671 * intra-verified (checked for internal consistency).
2672 */
2673static bool crossVerifyEverything(CheckState* state, DexMapList* pMap)
2674{
2675 const DexMapItem* item = pMap->list;
2676 u4 count = pMap->size;
2677 bool okay = true;
2678
2679 while (okay && count--) {
2680 u4 sectionOffset = item->offset;
2681 u4 sectionCount = item->size;
2682
2683 switch (item->type) {
2684 case kDexTypeHeaderItem:
2685 case kDexTypeMapList:
2686 case kDexTypeTypeList:
2687 case kDexTypeCodeItem:
2688 case kDexTypeStringDataItem:
2689 case kDexTypeDebugInfoItem:
2690 case kDexTypeAnnotationItem:
2691 case kDexTypeEncodedArrayItem: {
2692 // There is no need for cross-item verification for these.
2693 break;
2694 }
2695 case kDexTypeStringIdItem: {
2696 okay = iterateSection(state, sectionOffset, sectionCount,
2697 crossVerifyStringIdItem, sizeof(u4), NULL);
2698 break;
2699 }
2700 case kDexTypeTypeIdItem: {
2701 okay = iterateSection(state, sectionOffset, sectionCount,
2702 crossVerifyTypeIdItem, sizeof(u4), NULL);
2703 break;
2704 }
2705 case kDexTypeProtoIdItem: {
2706 okay = iterateSection(state, sectionOffset, sectionCount,
2707 crossVerifyProtoIdItem, sizeof(u4), NULL);
2708 break;
2709 }
2710 case kDexTypeFieldIdItem: {
2711 okay = iterateSection(state, sectionOffset, sectionCount,
2712 crossVerifyFieldIdItem, sizeof(u4), NULL);
2713 break;
2714 }
2715 case kDexTypeMethodIdItem: {
2716 okay = iterateSection(state, sectionOffset, sectionCount,
2717 crossVerifyMethodIdItem, sizeof(u4), NULL);
2718 break;
2719 }
2720 case kDexTypeClassDefItem: {
Dan Bornsteine02aff72010-01-26 12:58:08 -08002721 // Allocate (on the stack) the "observed class_def" bits.
2722 size_t arraySize = calcDefinedClassBitsSize(state);
2723 u4 definedClassBits[arraySize];
2724 memset(definedClassBits, 0, arraySize * sizeof(u4));
2725 state->pDefinedClassBits = definedClassBits;
2726
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002727 okay = iterateSection(state, sectionOffset, sectionCount,
2728 crossVerifyClassDefItem, sizeof(u4), NULL);
Dan Bornsteine02aff72010-01-26 12:58:08 -08002729
2730 state->pDefinedClassBits = NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002731 break;
2732 }
2733 case kDexTypeAnnotationSetRefList: {
2734 okay = iterateSection(state, sectionOffset, sectionCount,
2735 crossVerifyAnnotationSetRefList, sizeof(u4), NULL);
2736 break;
2737 }
2738 case kDexTypeAnnotationSetItem: {
2739 okay = iterateSection(state, sectionOffset, sectionCount,
2740 crossVerifyAnnotationSetItem, sizeof(u4), NULL);
2741 break;
2742 }
2743 case kDexTypeClassDataItem: {
2744 okay = iterateSection(state, sectionOffset, sectionCount,
2745 crossVerifyClassDataItem, sizeof(u1), NULL);
2746 break;
2747 }
2748 case kDexTypeAnnotationsDirectoryItem: {
2749 okay = iterateSection(state, sectionOffset, sectionCount,
2750 crossVerifyAnnotationsDirectoryItem, sizeof(u4), NULL);
2751 break;
2752 }
2753 default: {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002754 ALOGE("Unknown map item type %04x", item->type);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002755 return false;
2756 }
2757 }
2758
2759 if (!okay) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002760 ALOGE("Cross-item verify of section type %04x failed",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002761 item->type);
2762 }
2763
2764 item++;
2765 }
2766
2767 return okay;
2768}
2769
Dan Bornstein9fdbd912011-05-25 13:15:47 -07002770/* (documented in header file) */
2771bool dexHasValidMagic(const DexHeader* pHeader)
2772{
2773 const u1* magic = pHeader->magic;
2774 const u1* version = &magic[4];
2775
2776 if (memcmp(magic, DEX_MAGIC, 4) != 0) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002777 ALOGE("ERROR: unrecognized magic number (%02x %02x %02x %02x)",
Dan Bornstein9fdbd912011-05-25 13:15:47 -07002778 magic[0], magic[1], magic[2], magic[3]);
2779 return false;
2780 }
2781
2782 if ((memcmp(version, DEX_MAGIC_VERS, 4) != 0) &&
2783 (memcmp(version, DEX_MAGIC_VERS_API_13, 4) != 0)) {
2784 /*
2785 * Magic was correct, but this is an unsupported older or
2786 * newer format variant.
2787 */
Steve Blockc1a4ab92012-01-06 19:16:58 +00002788 ALOGE("ERROR: unsupported dex version (%02x %02x %02x %02x)",
Dan Bornstein9fdbd912011-05-25 13:15:47 -07002789 version[0], version[1], version[2], version[3]);
2790 return false;
2791 }
2792
2793 return true;
2794}
2795
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002796/*
Brian Carlstromfbdcfb92010-05-28 15:42:12 -07002797 * Fix the byte ordering of all fields in the DEX file, and do
2798 * structural verification. This is only required for code that opens
2799 * "raw" DEX files, such as the DEX optimizer.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002800 *
2801 * Returns 0 on success, nonzero on failure.
2802 */
Brian Carlstromfbdcfb92010-05-28 15:42:12 -07002803int dexSwapAndVerify(u1* addr, int len)
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002804{
2805 DexHeader* pHeader;
2806 CheckState state;
2807 bool okay = true;
2808
2809 memset(&state, 0, sizeof(state));
Steve Block92c1f6f2011-10-20 11:55:54 +01002810 ALOGV("+++ swapping and verifying");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002811
2812 /*
Dan Bornstein9fdbd912011-05-25 13:15:47 -07002813 * Note: The caller must have verified that "len" is at least as
2814 * large as a dex file header.
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002815 */
2816 pHeader = (DexHeader*) addr;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002817
Dan Bornstein9fdbd912011-05-25 13:15:47 -07002818 if (!dexHasValidMagic(pHeader)) {
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002819 okay = false;
2820 }
2821
2822 if (okay) {
2823 int expectedLen = (int) SWAP4(pHeader->fileSize);
2824 if (len < expectedLen) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002825 ALOGE("ERROR: Bad length: expected %d, got %d", expectedLen, len);
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002826 okay = false;
2827 } else if (len != expectedLen) {
Steve Blocke8e1ddc2012-01-05 23:21:27 +00002828 ALOGW("WARNING: Odd length: expected %d, got %d", expectedLen,
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002829 len);
2830 // keep going
2831 }
2832 }
2833
2834 if (okay) {
2835 /*
2836 * Compute the adler32 checksum and compare it to what's stored in
2837 * the file. This isn't free, but chances are good that we just
2838 * unpacked this from a jar file and have all of the pages sitting
2839 * in memory, so it's pretty quick.
2840 *
2841 * This might be a big-endian system, so we need to do this before
2842 * we byte-swap the header.
2843 */
2844 uLong adler = adler32(0L, Z_NULL, 0);
2845 const int nonSum = sizeof(pHeader->magic) + sizeof(pHeader->checksum);
2846 u4 storedFileSize = SWAP4(pHeader->fileSize);
2847 u4 expectedChecksum = SWAP4(pHeader->checksum);
2848
2849 adler = adler32(adler, ((const u1*) pHeader) + nonSum,
2850 storedFileSize - nonSum);
2851
2852 if (adler != expectedChecksum) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002853 ALOGE("ERROR: bad checksum (%08lx, expected %08x)",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002854 adler, expectedChecksum);
2855 okay = false;
2856 }
2857 }
2858
2859 if (okay) {
2860 state.fileStart = addr;
2861 state.fileEnd = addr + len;
2862 state.fileLen = len;
2863 state.pDexFile = NULL;
2864 state.pDataMap = NULL;
Dan Bornsteine02aff72010-01-26 12:58:08 -08002865 state.pDefinedClassBits = NULL;
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002866 state.previousItem = NULL;
2867
2868 /*
2869 * Swap the header and check the contents.
2870 */
2871 okay = swapDexHeader(&state, pHeader);
2872 }
2873
2874 if (okay) {
2875 state.pHeader = pHeader;
2876
2877 if (pHeader->headerSize < sizeof(DexHeader)) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002878 ALOGE("ERROR: Small header size %d, struct %d",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002879 pHeader->headerSize, (int) sizeof(DexHeader));
2880 okay = false;
2881 } else if (pHeader->headerSize > sizeof(DexHeader)) {
Steve Blocke8e1ddc2012-01-05 23:21:27 +00002882 ALOGW("WARNING: Large header size %d, struct %d",
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002883 pHeader->headerSize, (int) sizeof(DexHeader));
2884 // keep going?
2885 }
2886 }
2887
2888 if (okay) {
2889 /*
2890 * Look for the map. Swap it and then use it to find and swap
2891 * everything else.
2892 */
2893 if (pHeader->mapOff != 0) {
2894 DexFile dexFile;
2895 DexMapList* pDexMap = (DexMapList*) (addr + pHeader->mapOff);
2896
2897 okay = okay && swapMap(&state, pDexMap);
2898 okay = okay && swapEverythingButHeaderAndMap(&state, pDexMap);
2899
2900 dexFileSetupBasicPointers(&dexFile, addr);
2901 state.pDexFile = &dexFile;
2902
2903 okay = okay && crossVerifyEverything(&state, pDexMap);
2904 } else {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002905 ALOGE("ERROR: No map found; impossible to byte-swap and verify");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002906 okay = false;
2907 }
2908 }
2909
2910 if (!okay) {
Steve Blockc1a4ab92012-01-06 19:16:58 +00002911 ALOGE("ERROR: Byte swap + verify failed");
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002912 }
2913
2914 if (state.pDataMap != NULL) {
2915 dexDataMapFree(state.pDataMap);
2916 }
Dan Bornsteine02aff72010-01-26 12:58:08 -08002917
The Android Open Source Projectf6c38712009-03-03 19:28:47 -08002918 return !okay; // 0 == success
2919}
Brian Carlstromfbdcfb92010-05-28 15:42:12 -07002920
2921/*
2922 * Detect the file type of the given memory buffer via magic number.
2923 * Call dexSwapAndVerify() on an unoptimized DEX file, do nothing
2924 * but return successfully on an optimized DEX file, and report an
2925 * error for all other cases.
2926 *
2927 * Returns 0 on success, nonzero on failure.
2928 */
2929int dexSwapAndVerifyIfNecessary(u1* addr, int len)
2930{
2931 if (memcmp(addr, DEX_OPT_MAGIC, 4) == 0) {
2932 // It is an optimized dex file.
2933 return 0;
2934 }
2935
2936 if (memcmp(addr, DEX_MAGIC, 4) == 0) {
2937 // It is an unoptimized dex file.
2938 return dexSwapAndVerify(addr, len);
2939 }
2940
Steve Blockc1a4ab92012-01-06 19:16:58 +00002941 ALOGE("ERROR: Bad magic number (0x%02x %02x %02x %02x)",
Brian Carlstromfbdcfb92010-05-28 15:42:12 -07002942 addr[0], addr[1], addr[2], addr[3]);
2943
2944 return 1;
2945}