1 /*
2 * Copyright (C) 2008 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 /*
18 * 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
24
25 /* fwd */
26 static bool verifyMethod(Method* meth);
27 static bool verifyInstructions(VerifierData* vdata);
28
29
30 /*
31 * Initialize some things we need for verification.
32 */
dvmVerificationStartup(void)33 bool dvmVerificationStartup(void)
34 {
35 gDvm.instrWidth = dexCreateInstrWidthTable();
36 gDvm.instrFormat = dexCreateInstrFormatTable();
37 gDvm.instrFlags = dexCreateInstrFlagsTable();
38 if (gDvm.instrWidth == NULL || gDvm.instrFormat == NULL ||
39 gDvm.instrFlags == NULL)
40 {
41 LOGE("Unable to create instruction tables\n");
42 return false;
43 }
44
45 return true;
46 }
47
48 /*
49 * Free up some things we needed for verification.
50 */
dvmVerificationShutdown(void)51 void dvmVerificationShutdown(void)
52 {
53 free(gDvm.instrWidth);
54 free(gDvm.instrFormat);
55 free(gDvm.instrFlags);
56 }
57
58
59 /*
60 * Verify a class.
61 *
62 * By the time we get here, the value of gDvm.classVerifyMode should already
63 * have been factored in. If you want to call into the verifier even
64 * though verification is disabled, that's your business.
65 *
66 * Returns "true" on success.
67 */
dvmVerifyClass(ClassObject * clazz)68 bool dvmVerifyClass(ClassObject* clazz)
69 {
70 int i;
71
72 if (dvmIsClassVerified(clazz)) {
73 LOGD("Ignoring duplicate verify attempt on %s\n", clazz->descriptor);
74 return true;
75 }
76
77 for (i = 0; i < clazz->directMethodCount; i++) {
78 if (!verifyMethod(&clazz->directMethods[i])) {
79 LOG_VFY("Verifier rejected class %s\n", clazz->descriptor);
80 return false;
81 }
82 }
83 for (i = 0; i < clazz->virtualMethodCount; i++) {
84 if (!verifyMethod(&clazz->virtualMethods[i])) {
85 LOG_VFY("Verifier rejected class %s\n", clazz->descriptor);
86 return false;
87 }
88 }
89
90 return true;
91 }
92
93
94 /*
95 * Perform verification on a single method.
96 *
97 * We do this in three passes:
98 * (1) Walk through all code units, determining instruction locations,
99 * widths, and other characteristics.
100 * (2) Walk through all code units, performing static checks on
101 * operands.
102 * (3) Iterate through the method, checking type safety and looking
103 * for code flow problems.
104 *
105 * Some checks may be bypassed depending on the verification mode. We can't
106 * turn this stuff off completely if we want to do "exact" GC.
107 *
108 * TODO: cite source?
109 * Confirmed here:
110 * - code array must not be empty
111 * - (N/A) code_length must be less than 65536
112 * Confirmed by dvmComputeCodeWidths():
113 * - opcode of first instruction begins at index 0
114 * - only documented instructions may appear
115 * - each instruction follows the last
116 * - last byte of last instruction is at (code_length-1)
117 */
verifyMethod(Method * meth)118 static bool verifyMethod(Method* meth)
119 {
120 bool result = false;
121 int newInstanceCount;
122
123 /*
124 * Verifier state blob. Various values will be cached here so we
125 * can avoid expensive lookups and pass fewer arguments around.
126 */
127 VerifierData vdata;
128 #if 1 // ndef NDEBUG
129 memset(&vdata, 0x99, sizeof(vdata));
130 #endif
131
132 vdata.method = meth;
133 vdata.insnsSize = dvmGetMethodInsnsSize(meth);
134 vdata.insnRegCount = meth->registersSize;
135 vdata.insnFlags = NULL;
136 vdata.uninitMap = NULL;
137
138 /*
139 * If there aren't any instructions, make sure that's expected, then
140 * exit successfully. Note: for native methods, meth->insns gets set
141 * to a native function pointer on first call, so don't use that as
142 * an indicator.
143 */
144 if (vdata.insnsSize == 0) {
145 if (!dvmIsNativeMethod(meth) && !dvmIsAbstractMethod(meth)) {
146 LOG_VFY_METH(meth,
147 "VFY: zero-length code in concrete non-native method\n");
148 goto bail;
149 }
150
151 goto success;
152 }
153
154 /*
155 * Sanity-check the register counts. ins + locals = registers, so make
156 * sure that ins <= registers.
157 */
158 if (meth->insSize > meth->registersSize) {
159 LOG_VFY_METH(meth, "VFY: bad register counts (ins=%d regs=%d)\n",
160 meth->insSize, meth->registersSize);
161 goto bail;
162 }
163
164 /*
165 * Allocate and populate an array to hold instruction data.
166 *
167 * TODO: Consider keeping a reusable pre-allocated array sitting
168 * around for smaller methods.
169 */
170 vdata.insnFlags = (InsnFlags*)
171 calloc(dvmGetMethodInsnsSize(meth), sizeof(InsnFlags));
172 if (vdata.insnFlags == NULL)
173 goto bail;
174
175 /*
176 * Compute the width of each instruction and store the result in insnFlags.
177 * Count up the #of occurrences of new-instance instructions while we're
178 * at it.
179 */
180 if (!dvmComputeCodeWidths(meth, vdata.insnFlags, &newInstanceCount))
181 goto bail;
182
183 /*
184 * Allocate a map to hold the classes of uninitialized instances.
185 */
186 vdata.uninitMap = dvmCreateUninitInstanceMap(meth, vdata.insnFlags,
187 newInstanceCount);
188 if (vdata.uninitMap == NULL)
189 goto bail;
190
191 /*
192 * Set the "in try" flags for all instructions guarded by a "try" block.
193 */
194 if (!dvmSetTryFlags(meth, vdata.insnFlags))
195 goto bail;
196
197 /*
198 * Perform static instruction verification.
199 */
200 if (!verifyInstructions(&vdata))
201 goto bail;
202
203 /*
204 * Do code-flow analysis. Do this after verifying the branch targets
205 * so we don't need to worry about it here.
206 *
207 * If there are no registers, we don't need to do much in the way of
208 * analysis, but we still need to verify that nothing actually tries
209 * to use a register.
210 */
211 if (!dvmVerifyCodeFlow(&vdata)) {
212 //LOGD("+++ %s failed code flow\n", meth->name);
213 goto bail;
214 }
215
216 success:
217 result = true;
218
219 bail:
220 dvmFreeUninitInstanceMap(vdata.uninitMap);
221 free(vdata.insnFlags);
222 return result;
223 }
224
225
226 /*
227 * Verify an array data table. "curOffset" is the offset of the fill-array-data
228 * instruction.
229 */
checkArrayData(const Method * meth,int curOffset)230 static bool checkArrayData(const Method* meth, int curOffset)
231 {
232 const int insnCount = dvmGetMethodInsnsSize(meth);
233 const u2* insns = meth->insns + curOffset;
234 const u2* arrayData;
235 int valueCount, valueWidth, tableSize;
236 int offsetToArrayData;
237
238 assert(curOffset >= 0 && curOffset < insnCount);
239
240 /* make sure the start of the array data table is in range */
241 offsetToArrayData = insns[1] | (((s4)insns[2]) << 16);
242 if (curOffset + offsetToArrayData < 0 ||
243 curOffset + offsetToArrayData + 2 >= insnCount)
244 {
245 LOG_VFY_METH(meth,
246 "VFY: invalid array data start: at %d, data offset %d, count %d\n",
247 curOffset, offsetToArrayData, insnCount);
248 return false;
249 }
250
251 /* offset to array data table is a relative branch-style offset */
252 arrayData = insns + offsetToArrayData;
253
254 /* make sure the table is 32-bit aligned */
255 if ((((u4) arrayData) & 0x03) != 0) {
256 LOG_VFY_METH(meth,
257 "VFY: unaligned array data table: at %d, data offset %d\n",
258 curOffset, offsetToArrayData);
259 return false;
260 }
261
262 valueWidth = arrayData[1];
263 valueCount = *(u4*)(&arrayData[2]);
264
265 tableSize = 4 + (valueWidth * valueCount + 1) / 2;
266
267 /* make sure the end of the switch is in range */
268 if (curOffset + offsetToArrayData + tableSize > insnCount) {
269 LOG_VFY_METH(meth,
270 "VFY: invalid array data end: at %d, data offset %d, end %d, "
271 "count %d\n",
272 curOffset, offsetToArrayData,
273 curOffset + offsetToArrayData + tableSize,
274 insnCount);
275 return false;
276 }
277
278 return true;
279 }
280
281
282 /*
283 * Decode the current instruction.
284 */
decodeInstruction(const Method * meth,int insnIdx,DecodedInstruction * pDecInsn)285 static void decodeInstruction(const Method* meth, int insnIdx,
286 DecodedInstruction* pDecInsn)
287 {
288 dexDecodeInstruction(gDvm.instrFormat, meth->insns + insnIdx, pDecInsn);
289 }
290
291
292 /*
293 * Perform static checks on a "new-instance" instruction. Specifically,
294 * make sure the class reference isn't for an array class.
295 *
296 * We don't need the actual class, just a pointer to the class name.
297 */
checkNewInstance(const Method * meth,int insnIdx)298 static bool checkNewInstance(const Method* meth, int insnIdx)
299 {
300 DvmDex* pDvmDex = meth->clazz->pDvmDex;
301 DecodedInstruction decInsn;
302 const char* classDescriptor;
303 u4 idx;
304
305 decodeInstruction(meth, insnIdx, &decInsn);
306 idx = decInsn.vB; // 2nd item
307 if (idx >= pDvmDex->pHeader->typeIdsSize) {
308 LOG_VFY_METH(meth, "VFY: bad type index %d (max %d)\n",
309 idx, pDvmDex->pHeader->typeIdsSize);
310 return false;
311 }
312
313 classDescriptor = dexStringByTypeIdx(pDvmDex->pDexFile, idx);
314 if (classDescriptor[0] != 'L') {
315 LOG_VFY_METH(meth, "VFY: can't call new-instance on type '%s'\n",
316 classDescriptor);
317 return false;
318 }
319
320 return true;
321 }
322
323 /*
324 * Perform static checks on a "new-array" instruction. Specifically, make
325 * sure they aren't creating an array of arrays that causes the number of
326 * dimensions to exceed 255.
327 */
checkNewArray(const Method * meth,int insnIdx)328 static bool checkNewArray(const Method* meth, int insnIdx)
329 {
330 DvmDex* pDvmDex = meth->clazz->pDvmDex;
331 DecodedInstruction decInsn;
332 const char* classDescriptor;
333 u4 idx;
334
335 decodeInstruction(meth, insnIdx, &decInsn);
336 idx = decInsn.vC; // 3rd item
337 if (idx >= pDvmDex->pHeader->typeIdsSize) {
338 LOG_VFY_METH(meth, "VFY: bad type index %d (max %d)\n",
339 idx, pDvmDex->pHeader->typeIdsSize);
340 return false;
341 }
342
343 classDescriptor = dexStringByTypeIdx(pDvmDex->pDexFile, idx);
344
345 int bracketCount = 0;
346 const char* cp = classDescriptor;
347 while (*cp++ == '[')
348 bracketCount++;
349
350 if (bracketCount == 0) {
351 /* The given class must be an array type. */
352 LOG_VFY_METH(meth, "VFY: can't new-array class '%s' (not an array)\n",
353 classDescriptor);
354 return false;
355 } else if (bracketCount > 255) {
356 /* It is illegal to create an array of more than 255 dimensions. */
357 LOG_VFY_METH(meth, "VFY: can't new-array class '%s' (exceeds limit)\n",
358 classDescriptor);
359 return false;
360 }
361
362 return true;
363 }
364
365 /*
366 * Perform static checks on an instruction that takes a class constant.
367 * Ensure that the class index is in the valid range.
368 */
checkTypeIndex(const Method * meth,int insnIdx,bool useB)369 static bool checkTypeIndex(const Method* meth, int insnIdx, bool useB)
370 {
371 DvmDex* pDvmDex = meth->clazz->pDvmDex;
372 DecodedInstruction decInsn;
373 u4 idx;
374
375 decodeInstruction(meth, insnIdx, &decInsn);
376 if (useB)
377 idx = decInsn.vB;
378 else
379 idx = decInsn.vC;
380 if (idx >= pDvmDex->pHeader->typeIdsSize) {
381 LOG_VFY_METH(meth, "VFY: bad type index %d (max %d)\n",
382 idx, pDvmDex->pHeader->typeIdsSize);
383 return false;
384 }
385
386 return true;
387 }
388
389 /*
390 * Perform static checks on a field get or set instruction. All we do
391 * here is ensure that the field index is in the valid range.
392 */
checkFieldIndex(const Method * meth,int insnIdx,bool useB)393 static bool checkFieldIndex(const Method* meth, int insnIdx, bool useB)
394 {
395 DvmDex* pDvmDex = meth->clazz->pDvmDex;
396 DecodedInstruction decInsn;
397 u4 idx;
398
399 decodeInstruction(meth, insnIdx, &decInsn);
400 if (useB)
401 idx = decInsn.vB;
402 else
403 idx = decInsn.vC;
404 if (idx >= pDvmDex->pHeader->fieldIdsSize) {
405 LOG_VFY_METH(meth,
406 "VFY: bad field index %d (max %d) at offset 0x%04x\n",
407 idx, pDvmDex->pHeader->fieldIdsSize, insnIdx);
408 return false;
409 }
410
411 return true;
412 }
413
414 /*
415 * Perform static checks on a method invocation instruction. All we do
416 * here is ensure that the method index is in the valid range.
417 */
checkMethodIndex(const Method * meth,int insnIdx)418 static bool checkMethodIndex(const Method* meth, int insnIdx)
419 {
420 DvmDex* pDvmDex = meth->clazz->pDvmDex;
421 DecodedInstruction decInsn;
422
423 decodeInstruction(meth, insnIdx, &decInsn);
424 if (decInsn.vB >= pDvmDex->pHeader->methodIdsSize) {
425 LOG_VFY_METH(meth, "VFY: bad method index %d (max %d)\n",
426 decInsn.vB, pDvmDex->pHeader->methodIdsSize);
427 return false;
428 }
429
430 return true;
431 }
432
433 /*
434 * Perform static checks on a string constant instruction. All we do
435 * here is ensure that the string index is in the valid range.
436 */
checkStringIndex(const Method * meth,int insnIdx)437 static bool checkStringIndex(const Method* meth, int insnIdx)
438 {
439 DvmDex* pDvmDex = meth->clazz->pDvmDex;
440 DecodedInstruction decInsn;
441
442 decodeInstruction(meth, insnIdx, &decInsn);
443 if (decInsn.vB >= pDvmDex->pHeader->stringIdsSize) {
444 LOG_VFY_METH(meth, "VFY: bad string index %d (max %d)\n",
445 decInsn.vB, pDvmDex->pHeader->stringIdsSize);
446 return false;
447 }
448
449 return true;
450 }
451
452 /*
453 * Perform static verification on instructions.
454 *
455 * As a side effect, this sets the "branch target" flags in InsnFlags.
456 *
457 * "(CF)" items are handled during code-flow analysis.
458 *
459 * v3 4.10.1
460 * - target of each jump and branch instruction must be valid
461 * - targets of switch statements must be valid
462 * - (CF) operands referencing constant pool entries must be valid
463 * - (CF) operands of getfield, putfield, getstatic, putstatic must be valid
464 * - (new) verify operands of "quick" field ops
465 * - (CF) operands of method invocation instructions must be valid
466 * - (new) verify operands of "quick" method invoke ops
467 * - (CF) only invoke-direct can call a method starting with '<'
468 * - (CF) <clinit> must never be called explicitly
469 * - (CF) operands of instanceof, checkcast, new (and variants) must be valid
470 * - new-array[-type] limited to 255 dimensions
471 * - can't use "new" on an array class
472 * - (?) limit dimensions in multi-array creation
473 * - (CF) local variable load/store register values must be in valid range
474 *
475 * v3 4.11.1.2
476 * - branches must be within the bounds of the code array
477 * - targets of all control-flow instructions are the start of an instruction
478 * - (CF) register accesses fall within range of allocated registers
479 * - (N/A) access to constant pool must be of appropriate type
480 * - (CF) code does not end in the middle of an instruction
481 * - (CF) execution cannot fall off the end of the code
482 * - (earlier) for each exception handler, the "try" area must begin and
483 * end at the start of an instruction (end can be at the end of the code)
484 * - (earlier) for each exception handler, the handler must start at a valid
485 * instruction
486 *
487 * TODO: move some of the "CF" items in here for better performance (the
488 * code-flow analysis sometimes has to process the same instruction several
489 * times).
490 */
verifyInstructions(VerifierData * vdata)491 static bool verifyInstructions(VerifierData* vdata)
492 {
493 const Method* meth = vdata->method;
494 InsnFlags* insnFlags = vdata->insnFlags;
495 const size_t insnCount = vdata->insnsSize;
496 const u2* insns = meth->insns;
497 int i;
498
499 /* the start of the method is a "branch target" */
500 dvmInsnSetBranchTarget(insnFlags, 0, true);
501
502 for (i = 0; i < (int) insnCount; /**/) {
503 /*
504 * These types of instructions can be GC points. To support precise
505 * GC, all such instructions must export the PC in the interpreter,
506 * or the GC won't be able to identify the current PC for the thread.
507 */
508 static const int gcMask = kInstrCanBranch | kInstrCanSwitch |
509 kInstrCanThrow | kInstrCanReturn;
510
511 int width = dvmInsnGetWidth(insnFlags, i);
512 OpCode opcode = *insns & 0xff;
513 InstructionFlags opFlags = dexGetInstrFlags(gDvm.instrFlags, opcode);
514
515 if ((opFlags & gcMask) != 0) {
516 /*
517 * This instruction is probably a GC point. Branch instructions
518 * only qualify if they go backward, so we need to check the
519 * offset.
520 */
521 int offset = -1;
522 bool unused;
523 if (dvmGetBranchTarget(meth, insnFlags, i, &offset, &unused)) {
524 if (offset <= 0) {
525 dvmInsnSetGcPoint(insnFlags, i, true);
526 }
527 } else {
528 /* not a branch target */
529 dvmInsnSetGcPoint(insnFlags, i, true);
530 }
531 }
532
533 switch (opcode) {
534 case OP_NOP:
535 /* plain no-op or switch table data; nothing to do here */
536 break;
537
538 case OP_CONST_STRING:
539 case OP_CONST_STRING_JUMBO:
540 if (!checkStringIndex(meth, i))
541 return false;
542 break;
543
544 case OP_CONST_CLASS:
545 case OP_CHECK_CAST:
546 if (!checkTypeIndex(meth, i, true))
547 return false;
548 break;
549 case OP_INSTANCE_OF:
550 if (!checkTypeIndex(meth, i, false))
551 return false;
552 break;
553
554 case OP_PACKED_SWITCH:
555 case OP_SPARSE_SWITCH:
556 /* verify the associated table */
557 if (!dvmCheckSwitchTargets(meth, insnFlags, i))
558 return false;
559 break;
560
561 case OP_FILL_ARRAY_DATA:
562 /* verify the associated table */
563 if (!checkArrayData(meth, i))
564 return false;
565 break;
566
567 case OP_GOTO:
568 case OP_GOTO_16:
569 case OP_IF_EQ:
570 case OP_IF_NE:
571 case OP_IF_LT:
572 case OP_IF_GE:
573 case OP_IF_GT:
574 case OP_IF_LE:
575 case OP_IF_EQZ:
576 case OP_IF_NEZ:
577 case OP_IF_LTZ:
578 case OP_IF_GEZ:
579 case OP_IF_GTZ:
580 case OP_IF_LEZ:
581 /* check the destination */
582 if (!dvmCheckBranchTarget(meth, insnFlags, i, false))
583 return false;
584 break;
585 case OP_GOTO_32:
586 /* check the destination; self-branch is okay */
587 if (!dvmCheckBranchTarget(meth, insnFlags, i, true))
588 return false;
589 break;
590
591 case OP_NEW_INSTANCE:
592 if (!checkNewInstance(meth, i))
593 return false;
594 break;
595
596 case OP_NEW_ARRAY:
597 if (!checkNewArray(meth, i))
598 return false;
599 break;
600
601 case OP_FILLED_NEW_ARRAY:
602 if (!checkTypeIndex(meth, i, true))
603 return false;
604 break;
605 case OP_FILLED_NEW_ARRAY_RANGE:
606 if (!checkTypeIndex(meth, i, true))
607 return false;
608 break;
609
610 case OP_IGET:
611 case OP_IGET_WIDE:
612 case OP_IGET_OBJECT:
613 case OP_IGET_BOOLEAN:
614 case OP_IGET_BYTE:
615 case OP_IGET_CHAR:
616 case OP_IGET_SHORT:
617 case OP_IPUT:
618 case OP_IPUT_WIDE:
619 case OP_IPUT_OBJECT:
620 case OP_IPUT_BOOLEAN:
621 case OP_IPUT_BYTE:
622 case OP_IPUT_CHAR:
623 case OP_IPUT_SHORT:
624 /* check the field index */
625 if (!checkFieldIndex(meth, i, false))
626 return false;
627 break;
628 case OP_SGET:
629 case OP_SGET_WIDE:
630 case OP_SGET_OBJECT:
631 case OP_SGET_BOOLEAN:
632 case OP_SGET_BYTE:
633 case OP_SGET_CHAR:
634 case OP_SGET_SHORT:
635 case OP_SPUT:
636 case OP_SPUT_WIDE:
637 case OP_SPUT_OBJECT:
638 case OP_SPUT_BOOLEAN:
639 case OP_SPUT_BYTE:
640 case OP_SPUT_CHAR:
641 case OP_SPUT_SHORT:
642 /* check the field index */
643 if (!checkFieldIndex(meth, i, true))
644 return false;
645 break;
646
647 case OP_INVOKE_VIRTUAL:
648 case OP_INVOKE_SUPER:
649 case OP_INVOKE_DIRECT:
650 case OP_INVOKE_STATIC:
651 case OP_INVOKE_INTERFACE:
652 case OP_INVOKE_VIRTUAL_RANGE:
653 case OP_INVOKE_SUPER_RANGE:
654 case OP_INVOKE_DIRECT_RANGE:
655 case OP_INVOKE_STATIC_RANGE:
656 case OP_INVOKE_INTERFACE_RANGE:
657 /* check the method index */
658 if (!checkMethodIndex(meth, i))
659 return false;
660 break;
661
662 case OP_EXECUTE_INLINE:
663 case OP_INVOKE_DIRECT_EMPTY:
664 case OP_IGET_QUICK:
665 case OP_IGET_WIDE_QUICK:
666 case OP_IGET_OBJECT_QUICK:
667 case OP_IPUT_QUICK:
668 case OP_IPUT_WIDE_QUICK:
669 case OP_IPUT_OBJECT_QUICK:
670 case OP_INVOKE_VIRTUAL_QUICK:
671 case OP_INVOKE_VIRTUAL_QUICK_RANGE:
672 case OP_INVOKE_SUPER_QUICK:
673 case OP_INVOKE_SUPER_QUICK_RANGE:
674 LOG_VFY("VFY: not expecting optimized instructions\n");
675 return false;
676 break;
677
678 default:
679 /* nothing to do */
680 break;
681 }
682
683 assert(width > 0);
684 i += width;
685 insns += width;
686 }
687
688 /* make sure the last instruction ends at the end of the insn area */
689 if (i != (int) insnCount) {
690 LOG_VFY_METH(meth,
691 "VFY: code did not end when expected (end at %d, count %d)\n",
692 i, insnCount);
693 return false;
694 }
695
696 return true;
697 }
698