blob: 3b69e8326a8e6562c88ddf4cdab732a738a6009f [file] [log] [blame]
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -07001/*
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 */
The Android Open Source Project89c1feb2008-12-17 18:03:55 -080016
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -070017/*
18 * Dalvik classfile verification. This file contains the verifier entry
19 * points and the static constraint checks.
20 */
21#include "Dalvik.h"
22#include "analysis/CodeVerify.h"
23#include "libdex/DexCatch.h"
24#include "libdex/InstrUtils.h"
25
26//#define static
27
28/* verification failure reporting */
29#define LOG_VFY(...) dvmLogVerifyFailure(NULL, __VA_ARGS__);
30#define LOG_VFY_METH(_meth, ...) dvmLogVerifyFailure(_meth, __VA_ARGS__);
31
32
33/* fwd */
34static bool computeCodeWidths(const Method* meth, InsnFlags* insnFlags,\
35 int* pNewInstanceCount);
36static bool setTryFlags(const Method* meth, InsnFlags* insnFlags);
37static bool verifyMethod(Method* meth, int verifyFlags);
38static bool verifyInstructions(const Method* meth, InsnFlags* insnFlags,
39 int verifyFlags);
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -070040
41
42/*
43 * Initialize some things we need for verification.
44 */
45bool dvmVerificationStartup(void)
46{
47 gDvm.instrWidth = dexCreateInstrWidthTable();
48 gDvm.instrFormat = dexCreateInstrFormatTable();
49 gDvm.instrFlags = dexCreateInstrFlagsTable();
50 return (gDvm.instrWidth != NULL && gDvm.instrFormat!= NULL);
51}
52
53/*
54 * Initialize some things we need for verification.
55 */
56void dvmVerificationShutdown(void)
57{
58 free(gDvm.instrWidth);
59 free(gDvm.instrFormat);
60 free(gDvm.instrFlags);
61}
62
63/*
64 * Induce verification on all classes loaded from this DEX file as part
65 * of pre-verification and optimization. This is never called from a
66 * normally running VM.
67 *
68 * Returns "true" when all classes have been processed.
69 */
70bool dvmVerifyAllClasses(DexFile* pDexFile)
71{
72 u4 count = pDexFile->pHeader->classDefsSize;
73 u4 idx;
74
75 assert(gDvm.optimizing);
76
77 if (gDvm.classVerifyMode == VERIFY_MODE_NONE) {
78 LOGV("+++ verification is disabled, skipping all classes\n");
79 return true;
80 }
81 if (gDvm.classVerifyMode == VERIFY_MODE_REMOTE &&
82 gDvm.optimizingBootstrapClass)
83 {
84 LOGV("+++ verification disabled for bootstrap classes\n");
85 return true;
86 }
87
88 for (idx = 0; idx < count; idx++) {
89 const DexClassDef* pClassDef;
90 const char* classDescriptor;
91 ClassObject* clazz;
The Android Open Source Project89c1feb2008-12-17 18:03:55 -080092
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -070093 pClassDef = dexGetClassDef(pDexFile, idx);
94 classDescriptor = dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
95
96 /* all classes are loaded into the bootstrap class loader */
97 clazz = dvmLookupClass(classDescriptor, NULL, false);
98 if (clazz != NULL) {
99 if (clazz->pDvmDex->pDexFile != pDexFile) {
100 LOGD("DexOpt: not verifying '%s': multiple definitions\n",
101 classDescriptor);
102 } else {
103 if (dvmVerifyClass(clazz, VERIFY_DEFAULT)) {
104 assert((clazz->accessFlags & JAVA_FLAGS_MASK) ==
105 pClassDef->accessFlags);
106 ((DexClassDef*)pClassDef)->accessFlags |=
107 CLASS_ISPREVERIFIED;
108 }
109 /* keep going even if one fails */
110 }
111 } else {
112 LOGV("DexOpt: +++ not verifying '%s'\n", classDescriptor);
113 }
114 }
115
116 return true;
117}
118
119/*
120 * Verify a class.
121 *
122 * By the time we get here, the value of gDvm.classVerifyMode should already
123 * have been factored in. If you want to call into the verifier even
124 * though verification is disabled, that's your business.
125 *
126 * Returns "true" on success.
127 */
128bool dvmVerifyClass(ClassObject* clazz, int verifyFlags)
129{
130 int i;
131
132 if (dvmIsClassVerified(clazz)) {
133 LOGD("Ignoring duplicate verify attempt on %s\n", clazz->descriptor);
134 return true;
135 }
136
137 //LOGI("Verify1 '%s'\n", clazz->descriptor);
138
139 // TODO - verify class structure in DEX?
140
141 for (i = 0; i < clazz->directMethodCount; i++) {
142 if (!verifyMethod(&clazz->directMethods[i], verifyFlags)) {
143 LOG_VFY("Verifier rejected class %s\n", clazz->descriptor);
144 return false;
145 }
146 }
147 for (i = 0; i < clazz->virtualMethodCount; i++) {
148 if (!verifyMethod(&clazz->virtualMethods[i], verifyFlags)) {
149 LOG_VFY("Verifier rejected class %s\n", clazz->descriptor);
150 return false;
151 }
152 }
153
154 return true;
155}
156
157/*
158 * Perform verification on a single method.
159 *
160 * We do this in three passes:
161 * (1) Walk through all code units, determining instruction lengths.
162 * (2) Do static checks, including branch target and operand validation.
163 * (3) Do structural checks, including data-flow analysis.
164 *
165 * Some checks may be bypassed depending on the verification mode. We can't
166 * turn this stuff off completely if we want to do "exact" GC.
167 *
168 * - operands of getfield, putfield, getstatic, putstatic must be valid
169 * - operands of method invocation instructions must be valid
170 *
171 * - code array must not be empty
172 * - (N/A) code_length must be less than 65536
173 * - opcode of first instruction begins at index 0
174 * - only documented instructions may appear
175 * - each instruction follows the last
176 * - (below) last byte of last instruction is at (code_length-1)
177 */
178static bool verifyMethod(Method* meth, int verifyFlags)
179{
180 bool result = false;
181 UninitInstanceMap* uninitMap = NULL;
182 InsnFlags* insnFlags = NULL;
183 int i, newInstanceCount;
184
185 /*
186 * If there aren't any instructions, make sure that's expected, then
187 * exit successfully. Note: meth->insns gets set to a native function
188 * pointer on first call.
189 */
190 if (dvmGetMethodInsnsSize(meth) == 0) {
191 if (!dvmIsNativeMethod(meth) && !dvmIsAbstractMethod(meth)) {
192 LOG_VFY_METH(meth,
193 "VFY: zero-length code in concrete non-native method\n");
194 goto bail;
195 }
196
197 goto success;
198 }
The Android Open Source Project89c1feb2008-12-17 18:03:55 -0800199
200 /*
201 * Sanity-check the register counts. ins + locals = registers, so make
202 * sure that ins <= registers.
203 */
204 if (meth->insSize > meth->registersSize) {
205 LOG_VFY_METH(meth, "VFY: bad register counts (ins=%d regs=%d)\n",
206 meth->insSize, meth->registersSize);
207 goto bail;
208 }
209
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700210 /*
211 * Allocate and populate an array to hold instruction data.
212 *
213 * TODO: Consider keeping a reusable pre-allocated array sitting
214 * around for smaller methods.
215 */
216 insnFlags = (InsnFlags*)
217 calloc(dvmGetMethodInsnsSize(meth), sizeof(InsnFlags));
218 if (insnFlags == NULL)
219 goto bail;
220
221 /*
222 * Compute the width of each instruction and store the result in insnFlags.
223 * Count up the #of occurrences of new-instance instructions while we're
224 * at it.
225 */
226 if (!computeCodeWidths(meth, insnFlags, &newInstanceCount))
227 goto bail;
228
229 /*
230 * Allocate a map to hold the classes of uninitialized instances.
231 */
232 uninitMap = dvmCreateUninitInstanceMap(meth, insnFlags, newInstanceCount);
233 if (uninitMap == NULL)
234 goto bail;
235
236 /*
237 * Set the "in try" flags for all instructions guarded by a "try" block.
238 */
239 if (!setTryFlags(meth, insnFlags))
240 goto bail;
241
242 /*
243 * Perform static instruction verification.
244 */
245 if (!verifyInstructions(meth, insnFlags, verifyFlags))
246 goto bail;
247
248 /*
249 * Do code-flow analysis. Do this after verifying the branch targets
250 * so we don't need to worry about it here.
251 *
252 * If there are no registers, we don't need to do much in the way of
253 * analysis, but we still need to verify that nothing actually tries
254 * to use a register.
255 */
256 if (!dvmVerifyCodeFlow(meth, insnFlags, uninitMap)) {
257 //LOGD("+++ %s failed code flow\n", meth->name);
258 goto bail;
259 }
260
261success:
262 result = true;
263
264bail:
265 dvmFreeUninitInstanceMap(uninitMap);
266 free(insnFlags);
267 return result;
268}
269
270
271/*
272 * Compute the width of the instruction at each address in the instruction
273 * stream. Addresses that are in the middle of an instruction, or that
274 * are part of switch table data, are not set (so the caller should probably
275 * initialize "insnFlags" to zero).
276 *
277 * Logs an error and returns "false" on failure.
278 */
279static bool computeCodeWidths(const Method* meth, InsnFlags* insnFlags,
280 int* pNewInstanceCount)
281{
282 const int insnCount = dvmGetMethodInsnsSize(meth);
283 const u2* insns = meth->insns;
284 bool result = false;
285 int i;
286
287 *pNewInstanceCount = 0;
288
289 for (i = 0; i < insnCount; /**/) {
290 int width;
291
292 /*
The Android Open Source Project89c1feb2008-12-17 18:03:55 -0800293 * Switch tables and array data tables are identified with
294 * "extended NOP" opcodes. They contain no executable code,
295 * so we can just skip past them.
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700296 */
297 if (*insns == kPackedSwitchSignature) {
298 width = 4 + insns[1] * 2;
299 } else if (*insns == kSparseSwitchSignature) {
300 width = 2 + insns[1] * 4;
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700301 } else if (*insns == kArrayDataSignature) {
302 u4 size = insns[2] | (((u4)insns[3]) << 16);
303 width = 4 + (insns[1] * size + 1) / 2;
304 } else {
305 int instr = *insns & 0xff;
306 width = dexGetInstrWidthAbs(gDvm.instrWidth, instr);
307 if (width == 0) {
308 LOG_VFY_METH(meth,
309 "VFY: invalid post-opt instruction (0x%x)\n", instr);
310 goto bail;
311 }
312 if (width < 0 || width > 5) {
313 LOGE("VFY: bizarre width value %d\n", width);
314 dvmAbort();
315 }
316
317 if (instr == OP_NEW_INSTANCE)
318 (*pNewInstanceCount)++;
319 }
320
321 if (width > 65535) {
322 LOG_VFY_METH(meth, "VFY: insane width %d\n", width);
323 goto bail;
324 }
325
326 insnFlags[i] |= width;
327 i += width;
328 insns += width;
329 }
330 if (i != (int) dvmGetMethodInsnsSize(meth)) {
331 LOG_VFY_METH(meth, "VFY: code did not end where expected (%d vs. %d)\n",
332 i, dvmGetMethodInsnsSize(meth));
333 goto bail;
334 }
335
336 result = true;
337
338bail:
339 return result;
340}
341
342/*
343 * Set the "in try" flags for all instructions protected by "try" statements.
344 * Also sets the "branch target" flags for exception handlers.
345 *
346 * Call this after widths have been set in "insnFlags".
347 *
348 * Returns "false" if something in the exception table looks fishy, but
349 * we're expecting the exception table to be somewhat sane.
350 */
351static bool setTryFlags(const Method* meth, InsnFlags* insnFlags)
352{
353 u4 insnsSize = dvmGetMethodInsnsSize(meth);
354 DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile;
355 const DexCode* pCode = dvmGetMethodCode(meth);
356 u4 triesSize = pCode->triesSize;
357 const DexTry* pTries;
358 u4 handlersSize;
359 u4 offset;
360 u4 i;
361
362 if (triesSize == 0) {
363 return true;
364 }
365
366 pTries = dexGetTries(pCode);
367 handlersSize = dexGetHandlersSize(pCode);
368
369 for (i = 0; i < triesSize; i++) {
370 const DexTry* pTry = &pTries[i];
371 u4 start = pTry->startAddr;
372 u4 end = start + pTry->insnCount;
373 u4 addr;
374
375 if ((start >= end) || (start >= insnsSize) || (end > insnsSize)) {
376 LOG_VFY_METH(meth,
377 "VFY: bad exception entry: startAddr=%d endAddr=%d (size=%d)\n",
378 start, end, insnsSize);
379 return false;
380 }
381
382 if (dvmInsnGetWidth(insnFlags, start) == 0) {
383 LOG_VFY_METH(meth,
384 "VFY: 'try' block starts inside an instruction (%d)\n",
385 start);
386 return false;
387 }
388
389 for (addr = start; addr < end;
390 addr += dvmInsnGetWidth(insnFlags, addr))
391 {
392 assert(dvmInsnGetWidth(insnFlags, addr) != 0);
393 dvmInsnSetInTry(insnFlags, addr, true);
394 }
395 }
396
397 /* Iterate over each of the handlers to verify target addresses. */
398 offset = dexGetFirstHandlerOffset(pCode);
399 for (i = 0; i < handlersSize; i++) {
400 DexCatchIterator iterator;
401 dexCatchIteratorInit(&iterator, pCode, offset);
402
403 for (;;) {
404 DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
405 u4 addr;
The Android Open Source Project89c1feb2008-12-17 18:03:55 -0800406
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700407 if (handler == NULL) {
408 break;
409 }
410
411 addr = handler->address;
412 if (dvmInsnGetWidth(insnFlags, addr) == 0) {
413 LOG_VFY_METH(meth,
414 "VFY: exception handler starts at bad address (%d)\n",
415 addr);
416 return false;
417 }
The Android Open Source Project89c1feb2008-12-17 18:03:55 -0800418
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700419 dvmInsnSetBranchTarget(insnFlags, addr, true);
420 }
421
422 offset = dexCatchIteratorGetEndOffset(&iterator, pCode);
423 }
424
425 return true;
426}
427
428/*
429 * Verify a switch table. "curOffset" is the offset of the switch
430 * instruction.
431 */
432static bool checkSwitchTargets(const Method* meth, InsnFlags* insnFlags,
433 int curOffset)
434{
435 const int insnCount = dvmGetMethodInsnsSize(meth);
436 const u2* insns = meth->insns + curOffset;
437 const u2* switchInsns;
438 int switchCount, tableSize;
439 int offsetToSwitch, offsetToKeys, offsetToTargets, targ;
440 int offset, absOffset;
441
442 assert(curOffset >= 0 && curOffset < insnCount);
443
444 /* make sure the start of the switch is in range */
445 offsetToSwitch = (s2) insns[1];
446 if (curOffset + offsetToSwitch < 0 ||
447 curOffset + offsetToSwitch + 2 >= insnCount)
448 {
449 LOG_VFY_METH(meth,
450 "VFY: invalid switch start: at %d, switch offset %d, count %d\n",
451 curOffset, offsetToSwitch, insnCount);
452 return false;
453 }
454
455 /* offset to switch table is a relative branch-style offset */
456 switchInsns = insns + offsetToSwitch;
457
458 /* make sure the table is 32-bit aligned */
459 if ((((u4) switchInsns) & 0x03) != 0) {
460 LOG_VFY_METH(meth,
461 "VFY: unaligned switch table: at %d, switch offset %d\n",
462 curOffset, offsetToSwitch);
463 return false;
464 }
465
466 switchCount = switchInsns[1];
467
468 if ((*insns & 0xff) == OP_PACKED_SWITCH) {
469 /* 0=sig, 1=count, 2/3=firstKey */
470 offsetToTargets = 4;
471 offsetToKeys = -1;
472 } else {
473 /* 0=sig, 1=count, 2..count*2 = keys */
474 offsetToKeys = 2;
475 offsetToTargets = 2 + 2*switchCount;
476 }
477 tableSize = offsetToTargets + switchCount*2;
478
479 /* make sure the end of the switch is in range */
480 if (curOffset + offsetToSwitch + tableSize > insnCount) {
481 LOG_VFY_METH(meth,
482 "VFY: invalid switch end: at %d, switch offset %d, end %d, count %d\n",
483 curOffset, offsetToSwitch, curOffset + offsetToSwitch + tableSize,
484 insnCount);
485 return false;
486 }
487
488 /* for a sparse switch, verify the keys are in ascending order */
489 if (offsetToKeys > 0 && switchCount > 1) {
490 s4 lastKey;
The Android Open Source Project89c1feb2008-12-17 18:03:55 -0800491
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700492 lastKey = switchInsns[offsetToKeys] |
493 (switchInsns[offsetToKeys+1] << 16);
494 for (targ = 1; targ < switchCount; targ++) {
495 s4 key = (s4) switchInsns[offsetToKeys + targ*2] |
496 (s4) (switchInsns[offsetToKeys + targ*2 +1] << 16);
497 if (key <= lastKey) {
498 LOG_VFY_METH(meth,
499 "VFY: invalid packed switch: last key=%d, this=%d\n",
500 lastKey, key);
501 return false;
502 }
503
504 lastKey = key;
505 }
506 }
507
508 /* verify each switch target */
509 for (targ = 0; targ < switchCount; targ++) {
510 offset = (s4) switchInsns[offsetToTargets + targ*2] |
511 (s4) (switchInsns[offsetToTargets + targ*2 +1] << 16);
512 absOffset = curOffset + offset;
513
514 if (absOffset < 0 || absOffset >= insnCount ||
515 !dvmInsnIsOpcode(insnFlags, absOffset))
516 {
517 LOG_VFY_METH(meth,
518 "VFY: invalid switch target %d (-> 0x%x) at 0x%x[%d]\n",
519 offset, absOffset, curOffset, targ);
520 return false;
521 }
522 dvmInsnSetBranchTarget(insnFlags, absOffset, true);
523 }
524
525 return true;
526}
527
528/*
529 * Verify an array data table. "curOffset" is the offset of the fill-array-data
530 * instruction.
531 */
532static bool checkArrayData(const Method* meth, int curOffset)
533{
534 const int insnCount = dvmGetMethodInsnsSize(meth);
535 const u2* insns = meth->insns + curOffset;
536 const u2* arrayData;
537 int valueCount, valueWidth, tableSize;
538 int offsetToArrayData;
539
540 assert(curOffset >= 0 && curOffset < insnCount);
541
542 /* make sure the start of the array data table is in range */
543 offsetToArrayData = insns[1] | (((s4)insns[2]) << 16);
544 if (curOffset + offsetToArrayData < 0 ||
545 curOffset + offsetToArrayData + 2 >= insnCount)
546 {
547 LOG_VFY_METH(meth,
548 "VFY: invalid array data start: at %d, data offset %d, count %d\n",
549 curOffset, offsetToArrayData, insnCount);
550 return false;
551 }
552
553 /* offset to array data table is a relative branch-style offset */
554 arrayData = insns + offsetToArrayData;
555
556 /* make sure the table is 32-bit aligned */
557 if ((((u4) arrayData) & 0x03) != 0) {
558 LOG_VFY_METH(meth,
559 "VFY: unaligned array data table: at %d, data offset %d\n",
560 curOffset, offsetToArrayData);
561 return false;
562 }
563
564 valueWidth = arrayData[1];
565 valueCount = *(u4*)(&arrayData[2]);
566
567 tableSize = 4 + (valueWidth * valueCount + 1) / 2;
568
569 /* make sure the end of the switch is in range */
570 if (curOffset + offsetToArrayData + tableSize > insnCount) {
571 LOG_VFY_METH(meth,
572 "VFY: invalid array data end: at %d, data offset %d, end %d, "
573 "count %d\n",
574 curOffset, offsetToArrayData,
575 curOffset + offsetToArrayData + tableSize,
576 insnCount);
577 return false;
578 }
579
580 return true;
581}
582
583/*
584 * Verify that the target of a branch instruction is valid.
585 *
586 * We don't expect code to jump directly into an exception handler, but
587 * it's valid to do so as long as the target isn't a "move-exception"
588 * instruction. We verify that in a later stage.
589 *
590 * The VM spec doesn't forbid an instruction from branching to itself,
591 * but the Dalvik spec declares that only certain instructions can do so.
592 */
593static bool checkBranchTarget(const Method* meth, InsnFlags* insnFlags,
594 int curOffset, bool selfOkay)
595{
596 const int insnCount = dvmGetMethodInsnsSize(meth);
597 const u2* insns = meth->insns + curOffset;
598 int offset, absOffset;
599 bool isConditional;
600
601 if (!dvmGetBranchTarget(meth, insnFlags, curOffset, &offset,
602 &isConditional))
603 return false;
604
605 if (!selfOkay && offset == 0) {
606 LOG_VFY_METH(meth, "VFY: branch offset of zero not allowed at 0x%x\n",
607 curOffset);
608 return false;
609 }
610
611 /*
612 * Check for 32-bit overflow. This isn't strictly necessary if we can
613 * depend on the VM to have identical "wrap-around" behavior, but
614 * it's unwise to depend on that.
615 */
616 if (((s8) curOffset + (s8) offset) != (s8)(curOffset + offset)) {
617 LOG_VFY_METH(meth, "VFY: branch target overflow 0x%x +%d\n",
618 curOffset, offset);
619 return false;
620 }
621 absOffset = curOffset + offset;
622 if (absOffset < 0 || absOffset >= insnCount ||
623 !dvmInsnIsOpcode(insnFlags, absOffset))
624 {
625 LOG_VFY_METH(meth,
626 "VFY: invalid branch target %d (-> 0x%x) at 0x%x\n",
627 offset, absOffset, curOffset);
628 return false;
629 }
630 dvmInsnSetBranchTarget(insnFlags, absOffset, true);
631
632 return true;
633}
634
The Android Open Source Project89c1feb2008-12-17 18:03:55 -0800635
636/*
637 * Decode the current instruction.
638 */
639static void decodeInstruction(const Method* meth, int insnIdx,
640 DecodedInstruction* pDecInsn)
641{
642 dexDecodeInstruction(gDvm.instrFormat, meth->insns + insnIdx, pDecInsn);
643}
644
645
646/*
647 * Perform static checks on a "new-instance" instruction. Specifically,
648 * make sure the class reference isn't for an array class.
649 *
650 * We don't need the actual class, just a pointer to the class name.
651 */
652static bool checkNewInstance(const Method* meth, int insnIdx)
653{
654 DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile;
655 DecodedInstruction decInsn;
656 const char* classDescriptor;
657
658 decodeInstruction(meth, insnIdx, &decInsn);
659 classDescriptor = dexStringByTypeIdx(pDexFile, decInsn.vB); // 2nd item
660
661 if (classDescriptor[0] != 'L') {
662 LOG_VFY_METH(meth, "VFY: can't call new-instance on type '%s'\n",
663 classDescriptor);
664 return false;
665 }
666
667 return true;
668}
669
670/*
671 * Perform static checks on a "new-array" instruction. Specifically, make
672 * sure they aren't creating an array of arrays that causes the number of
673 * dimensions to exceed 255.
674 */
675static bool checkNewArray(const Method* meth, int insnIdx)
676{
677 DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile;
678 DecodedInstruction decInsn;
679 const char* classDescriptor;
680
681 decodeInstruction(meth, insnIdx, &decInsn);
682 classDescriptor = dexStringByTypeIdx(pDexFile, decInsn.vC); // 3rd item
683
684 int bracketCount = 0;
685 const char* cp = classDescriptor;
686 while (*cp++ == '[')
687 bracketCount++;
688
689 if (bracketCount == 0) {
690 /* The given class must be an array type. */
691 LOG_VFY_METH(meth, "VFY: can't new-array class '%s' (not an array)\n",
692 classDescriptor);
693 return false;
694 } else if (bracketCount > 255) {
695 /* It is illegal to create an array of more than 255 dimensions. */
696 LOG_VFY_METH(meth, "VFY: can't new-array class '%s' (exceeds limit)\n",
697 classDescriptor);
698 return false;
699 }
700
701 return true;
702}
703
704/*
705 * Perform static checks on an instruction that takes a class constant.
706 * Ensure that the class index is in the valid range.
707 */
708static bool checkTypeIndex(const Method* meth, int insnIdx, bool useB)
709{
710 DvmDex* pDvmDex = meth->clazz->pDvmDex;
711 DecodedInstruction decInsn;
712 u4 idx;
713
714 decodeInstruction(meth, insnIdx, &decInsn);
715 if (useB)
716 idx = decInsn.vB;
717 else
718 idx = decInsn.vC;
719 if (idx >= pDvmDex->pHeader->typeIdsSize) {
720 LOG_VFY_METH(meth, "VFY: bad type index %d (max %d)\n",
721 idx, pDvmDex->pHeader->typeIdsSize);
722 return false;
723 }
724
725 return true;
726}
727
728/*
729 * Perform static checks on a field get or set instruction. All we do
730 * here is ensure that the field index is in the valid range.
731 */
732static bool checkFieldIndex(const Method* meth, int insnIdx, bool useB)
733{
734 DvmDex* pDvmDex = meth->clazz->pDvmDex;
735 DecodedInstruction decInsn;
736 u4 idx;
737
738 decodeInstruction(meth, insnIdx, &decInsn);
739 if (useB)
740 idx = decInsn.vB;
741 else
742 idx = decInsn.vC;
743 if (idx >= pDvmDex->pHeader->fieldIdsSize) {
744 LOG_VFY_METH(meth,
745 "VFY: bad field index %d (max %d) at offset 0x%04x\n",
746 idx, pDvmDex->pHeader->fieldIdsSize, insnIdx);
747 return false;
748 }
749
750 return true;
751}
752
753/*
754 * Perform static checks on a method invocation instruction. All we do
755 * here is ensure that the method index is in the valid range.
756 */
757static bool checkMethodIndex(const Method* meth, int insnIdx)
758{
759 DvmDex* pDvmDex = meth->clazz->pDvmDex;
760 DecodedInstruction decInsn;
761
762 decodeInstruction(meth, insnIdx, &decInsn);
763 if (decInsn.vB >= pDvmDex->pHeader->methodIdsSize) {
764 LOG_VFY_METH(meth, "VFY: bad method index %d (max %d)\n",
765 decInsn.vB, pDvmDex->pHeader->methodIdsSize);
766 return false;
767 }
768
769 return true;
770}
771
772/*
773 * Perform static checks on a string constant instruction. All we do
774 * here is ensure that the string index is in the valid range.
775 */
776static bool checkStringIndex(const Method* meth, int insnIdx)
777{
778 DvmDex* pDvmDex = meth->clazz->pDvmDex;
779 DecodedInstruction decInsn;
780
781 decodeInstruction(meth, insnIdx, &decInsn);
782 if (decInsn.vB >= pDvmDex->pHeader->stringIdsSize) {
783 LOG_VFY_METH(meth, "VFY: bad string index %d (max %d)\n",
784 decInsn.vB, pDvmDex->pHeader->stringIdsSize);
785 return false;
786 }
787
788 return true;
789}
790
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700791/*
792 * Perform static verification on instructions.
793 *
794 * As a side effect, this sets the "branch target" flags in InsnFlags.
795 *
796 * "(CF)" items are handled during code-flow analysis.
797 *
798 * v3 4.10.1
799 * - target of each jump and branch instruction must be valid
800 * - targets of switch statements must be valid
801 * - (CF) operands referencing constant pool entries must be valid
802 * - (CF) operands of getfield, putfield, getstatic, putstatic must be valid
803 * - (new) verify operands of "quick" field ops
804 * - (CF) operands of method invocation instructions must be valid
805 * - (new) verify operands of "quick" method invoke ops
806 * - (CF) only invoke-direct can call a method starting with '<'
807 * - (CF) <clinit> must never be called explicitly
808 * - (CF) operands of instanceof, checkcast, new (and variants) must be valid
809 * - new-array[-type] limited to 255 dimensions
810 * - can't use "new" on an array class
811 * - (?) limit dimensions in multi-array creation
812 * - (CF) local variable load/store register values must be in valid range
813 *
814 * v3 4.11.1.2
815 * - branches must be within the bounds of the code array
816 * - targets of all control-flow instructions are the start of an instruction
817 * - (CF) register accesses fall within range of allocated registers
818 * - (N/A) access to constant pool must be of appropriate type
819 * - (CF) code does not end in the middle of an instruction
820 * - (CF) execution cannot fall off the end of the code
821 * - (earlier) for each exception handler, the "try" area must begin and
822 * end at the start of an instruction (end can be at the end of the code)
823 * - (earlier) for each exception handler, the handler must start at a valid
824 * instruction
The Android Open Source Project89c1feb2008-12-17 18:03:55 -0800825 *
826 * TODO: move some of the "CF" items in here for better performance (the
827 * code-flow analysis sometimes has to process the same instruction several
828 * times).
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700829 */
830static bool verifyInstructions(const Method* meth, InsnFlags* insnFlags,
831 int verifyFlags)
832{
833 const int insnCount = dvmGetMethodInsnsSize(meth);
834 const u2* insns = meth->insns;
835 int i, width, offset, absOffset;
836
837 /* the start of the method is a "branch target" */
838 dvmInsnSetBranchTarget(insnFlags, 0, true);
839
840 for (i = 0; i < insnCount; /**/) {
841 width = dvmInsnGetWidth(insnFlags, i);
842
843 switch (*insns & 0xff) {
844 case OP_NOP:
845 /* plain no-op or switch table data; nothing to do here */
846 break;
847
The Android Open Source Project89c1feb2008-12-17 18:03:55 -0800848 case OP_CONST_STRING:
849 case OP_CONST_STRING_JUMBO:
850 if (!checkStringIndex(meth, i))
851 return false;
852 break;
853
854 case OP_CONST_CLASS:
855 case OP_CHECK_CAST:
856 if (!checkTypeIndex(meth, i, true))
857 return false;
858 break;
859 case OP_INSTANCE_OF:
860 if (!checkTypeIndex(meth, i, false))
861 return false;
862 break;
863
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700864 case OP_PACKED_SWITCH:
865 case OP_SPARSE_SWITCH:
866 /* verify the associated table */
867 if (!checkSwitchTargets(meth, insnFlags, i))
868 return false;
869 break;
870
871 case OP_FILL_ARRAY_DATA:
872 /* verify the associated table */
873 if (!checkArrayData(meth, i))
874 return false;
875 break;
The Android Open Source Project89c1feb2008-12-17 18:03:55 -0800876
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700877 case OP_GOTO:
878 case OP_GOTO_16:
879 case OP_IF_EQ:
880 case OP_IF_NE:
881 case OP_IF_LT:
882 case OP_IF_GE:
883 case OP_IF_GT:
884 case OP_IF_LE:
885 case OP_IF_EQZ:
886 case OP_IF_NEZ:
887 case OP_IF_LTZ:
888 case OP_IF_GEZ:
889 case OP_IF_GTZ:
890 case OP_IF_LEZ:
891 /* check the destination */
892 if (!checkBranchTarget(meth, insnFlags, i, false))
893 return false;
894 break;
895 case OP_GOTO_32:
896 /* check the destination; self-branch is okay */
897 if (!checkBranchTarget(meth, insnFlags, i, true))
898 return false;
899 break;
900
901 case OP_NEW_INSTANCE:
902 if (!checkNewInstance(meth, i))
903 return false;
904 break;
905
906 case OP_NEW_ARRAY:
907 if (!checkNewArray(meth, i))
908 return false;
909 break;
910
The Android Open Source Project89c1feb2008-12-17 18:03:55 -0800911 case OP_FILLED_NEW_ARRAY:
912 if (!checkTypeIndex(meth, i, false))
913 return false;
914 break;
915 case OP_FILLED_NEW_ARRAY_RANGE:
916 if (!checkTypeIndex(meth, i, true))
917 return false;
918 break;
919
920 case OP_IGET:
921 case OP_IGET_WIDE:
922 case OP_IGET_OBJECT:
923 case OP_IGET_BOOLEAN:
924 case OP_IGET_BYTE:
925 case OP_IGET_CHAR:
926 case OP_IGET_SHORT:
927 case OP_IPUT:
928 case OP_IPUT_WIDE:
929 case OP_IPUT_OBJECT:
930 case OP_IPUT_BOOLEAN:
931 case OP_IPUT_BYTE:
932 case OP_IPUT_CHAR:
933 case OP_IPUT_SHORT:
934 /* check the field index */
935 if (!checkFieldIndex(meth, i, false))
936 return false;
937 break;
938 case OP_SGET:
939 case OP_SGET_WIDE:
940 case OP_SGET_OBJECT:
941 case OP_SGET_BOOLEAN:
942 case OP_SGET_BYTE:
943 case OP_SGET_CHAR:
944 case OP_SGET_SHORT:
945 case OP_SPUT:
946 case OP_SPUT_WIDE:
947 case OP_SPUT_OBJECT:
948 case OP_SPUT_BOOLEAN:
949 case OP_SPUT_BYTE:
950 case OP_SPUT_CHAR:
951 case OP_SPUT_SHORT:
952 /* check the field index */
953 if (!checkFieldIndex(meth, i, true))
954 return false;
955 break;
956
957 case OP_INVOKE_VIRTUAL:
958 case OP_INVOKE_SUPER:
959 case OP_INVOKE_DIRECT:
960 case OP_INVOKE_STATIC:
961 case OP_INVOKE_INTERFACE:
962 case OP_INVOKE_VIRTUAL_RANGE:
963 case OP_INVOKE_SUPER_RANGE:
964 case OP_INVOKE_DIRECT_RANGE:
965 case OP_INVOKE_STATIC_RANGE:
966 case OP_INVOKE_INTERFACE_RANGE:
967 /* check the method index */
968 if (!checkMethodIndex(meth, i))
969 return false;
970 break;
971
The Android Open Source Project2ad60cf2008-10-21 07:00:00 -0700972 case OP_EXECUTE_INLINE:
973 case OP_INVOKE_DIRECT_EMPTY:
974 case OP_IGET_QUICK:
975 case OP_IGET_WIDE_QUICK:
976 case OP_IGET_OBJECT_QUICK:
977 case OP_IPUT_QUICK:
978 case OP_IPUT_WIDE_QUICK:
979 case OP_IPUT_OBJECT_QUICK:
980 case OP_INVOKE_VIRTUAL_QUICK:
981 case OP_INVOKE_VIRTUAL_QUICK_RANGE:
982 case OP_INVOKE_SUPER_QUICK:
983 case OP_INVOKE_SUPER_QUICK_RANGE:
984 if ((verifyFlags & VERIFY_ALLOW_OPT_INSTRS) == 0) {
985 LOG_VFY("VFY: not expecting optimized instructions\n");
986 return false;
987 }
988 break;
989
990 default:
991 /* nothing to do */
992 break;
993 }
994
995 assert(width > 0);
996 i += width;
997 insns += width;
998 }
999
1000 /* make sure the last instruction ends at the end of the insn area */
1001 if (i != insnCount) {
1002 LOG_VFY_METH(meth,
1003 "VFY: code did not end when expected (end at %d, count %d)\n",
1004 i, insnCount);
1005 return false;
1006 }
1007
1008 return true;
1009}