Code drop from //branches/cupcake/...@124589
diff --git a/vm/analysis/DexVerify.c b/vm/analysis/DexVerify.c
index ab1e50b..3b69e83 100644
--- a/vm/analysis/DexVerify.c
+++ b/vm/analysis/DexVerify.c
@@ -13,6 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
/*
* Dalvik classfile verification. This file contains the verifier entry
* points and the static constraint checks.
@@ -36,8 +37,6 @@
static bool verifyMethod(Method* meth, int verifyFlags);
static bool verifyInstructions(const Method* meth, InsnFlags* insnFlags,
int verifyFlags);
-static bool checkNewInstance(const Method* meth, int insnIdx);
-static bool checkNewArray(const Method* meth, int insnIdx);
/*
@@ -90,7 +89,7 @@
const DexClassDef* pClassDef;
const char* classDescriptor;
ClassObject* clazz;
-
+
pClassDef = dexGetClassDef(pDexFile, idx);
classDescriptor = dexStringByTypeIdx(pDexFile, pClassDef->classIdx);
@@ -197,7 +196,17 @@
goto success;
}
-
+
+ /*
+ * Sanity-check the register counts. ins + locals = registers, so make
+ * sure that ins <= registers.
+ */
+ if (meth->insSize > meth->registersSize) {
+ LOG_VFY_METH(meth, "VFY: bad register counts (ins=%d regs=%d)\n",
+ meth->insSize, meth->registersSize);
+ goto bail;
+ }
+
/*
* Allocate and populate an array to hold instruction data.
*
@@ -281,16 +290,14 @@
int width;
/*
- * Switch tables are identified with "extended NOP" opcodes. They
- * contain no executable code, so we can just skip past them.
+ * Switch tables and array data tables are identified with
+ * "extended NOP" opcodes. They contain no executable code,
+ * so we can just skip past them.
*/
if (*insns == kPackedSwitchSignature) {
width = 4 + insns[1] * 2;
} else if (*insns == kSparseSwitchSignature) {
width = 2 + insns[1] * 4;
- /*
- * Array data table is identified with similar extended NOP opcode.
- */
} else if (*insns == kArrayDataSignature) {
u4 size = insns[2] | (((u4)insns[3]) << 16);
width = 4 + (insns[1] * size + 1) / 2;
@@ -396,7 +403,7 @@
for (;;) {
DexCatchHandler* handler = dexCatchIteratorNext(&iterator);
u4 addr;
-
+
if (handler == NULL) {
break;
}
@@ -408,7 +415,7 @@
addr);
return false;
}
-
+
dvmInsnSetBranchTarget(insnFlags, addr, true);
}
@@ -481,7 +488,7 @@
/* for a sparse switch, verify the keys are in ascending order */
if (offsetToKeys > 0 && switchCount > 1) {
s4 lastKey;
-
+
lastKey = switchInsns[offsetToKeys] |
(switchInsns[offsetToKeys+1] << 16);
for (targ = 1; targ < switchCount; targ++) {
@@ -625,6 +632,162 @@
return true;
}
+
+/*
+ * Decode the current instruction.
+ */
+static void decodeInstruction(const Method* meth, int insnIdx,
+ DecodedInstruction* pDecInsn)
+{
+ dexDecodeInstruction(gDvm.instrFormat, meth->insns + insnIdx, pDecInsn);
+}
+
+
+/*
+ * Perform static checks on a "new-instance" instruction. Specifically,
+ * make sure the class reference isn't for an array class.
+ *
+ * We don't need the actual class, just a pointer to the class name.
+ */
+static bool checkNewInstance(const Method* meth, int insnIdx)
+{
+ DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile;
+ DecodedInstruction decInsn;
+ const char* classDescriptor;
+
+ decodeInstruction(meth, insnIdx, &decInsn);
+ classDescriptor = dexStringByTypeIdx(pDexFile, decInsn.vB); // 2nd item
+
+ if (classDescriptor[0] != 'L') {
+ LOG_VFY_METH(meth, "VFY: can't call new-instance on type '%s'\n",
+ classDescriptor);
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * Perform static checks on a "new-array" instruction. Specifically, make
+ * sure they aren't creating an array of arrays that causes the number of
+ * dimensions to exceed 255.
+ */
+static bool checkNewArray(const Method* meth, int insnIdx)
+{
+ DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile;
+ DecodedInstruction decInsn;
+ const char* classDescriptor;
+
+ decodeInstruction(meth, insnIdx, &decInsn);
+ classDescriptor = dexStringByTypeIdx(pDexFile, decInsn.vC); // 3rd item
+
+ int bracketCount = 0;
+ const char* cp = classDescriptor;
+ while (*cp++ == '[')
+ bracketCount++;
+
+ if (bracketCount == 0) {
+ /* The given class must be an array type. */
+ LOG_VFY_METH(meth, "VFY: can't new-array class '%s' (not an array)\n",
+ classDescriptor);
+ return false;
+ } else if (bracketCount > 255) {
+ /* It is illegal to create an array of more than 255 dimensions. */
+ LOG_VFY_METH(meth, "VFY: can't new-array class '%s' (exceeds limit)\n",
+ classDescriptor);
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * Perform static checks on an instruction that takes a class constant.
+ * Ensure that the class index is in the valid range.
+ */
+static bool checkTypeIndex(const Method* meth, int insnIdx, bool useB)
+{
+ DvmDex* pDvmDex = meth->clazz->pDvmDex;
+ DecodedInstruction decInsn;
+ u4 idx;
+
+ decodeInstruction(meth, insnIdx, &decInsn);
+ if (useB)
+ idx = decInsn.vB;
+ else
+ idx = decInsn.vC;
+ if (idx >= pDvmDex->pHeader->typeIdsSize) {
+ LOG_VFY_METH(meth, "VFY: bad type index %d (max %d)\n",
+ idx, pDvmDex->pHeader->typeIdsSize);
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * Perform static checks on a field get or set instruction. All we do
+ * here is ensure that the field index is in the valid range.
+ */
+static bool checkFieldIndex(const Method* meth, int insnIdx, bool useB)
+{
+ DvmDex* pDvmDex = meth->clazz->pDvmDex;
+ DecodedInstruction decInsn;
+ u4 idx;
+
+ decodeInstruction(meth, insnIdx, &decInsn);
+ if (useB)
+ idx = decInsn.vB;
+ else
+ idx = decInsn.vC;
+ if (idx >= pDvmDex->pHeader->fieldIdsSize) {
+ LOG_VFY_METH(meth,
+ "VFY: bad field index %d (max %d) at offset 0x%04x\n",
+ idx, pDvmDex->pHeader->fieldIdsSize, insnIdx);
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * Perform static checks on a method invocation instruction. All we do
+ * here is ensure that the method index is in the valid range.
+ */
+static bool checkMethodIndex(const Method* meth, int insnIdx)
+{
+ DvmDex* pDvmDex = meth->clazz->pDvmDex;
+ DecodedInstruction decInsn;
+
+ decodeInstruction(meth, insnIdx, &decInsn);
+ if (decInsn.vB >= pDvmDex->pHeader->methodIdsSize) {
+ LOG_VFY_METH(meth, "VFY: bad method index %d (max %d)\n",
+ decInsn.vB, pDvmDex->pHeader->methodIdsSize);
+ return false;
+ }
+
+ return true;
+}
+
+/*
+ * Perform static checks on a string constant instruction. All we do
+ * here is ensure that the string index is in the valid range.
+ */
+static bool checkStringIndex(const Method* meth, int insnIdx)
+{
+ DvmDex* pDvmDex = meth->clazz->pDvmDex;
+ DecodedInstruction decInsn;
+
+ decodeInstruction(meth, insnIdx, &decInsn);
+ if (decInsn.vB >= pDvmDex->pHeader->stringIdsSize) {
+ LOG_VFY_METH(meth, "VFY: bad string index %d (max %d)\n",
+ decInsn.vB, pDvmDex->pHeader->stringIdsSize);
+ return false;
+ }
+
+ return true;
+}
+
/*
* Perform static verification on instructions.
*
@@ -659,6 +822,10 @@
* end at the start of an instruction (end can be at the end of the code)
* - (earlier) for each exception handler, the handler must start at a valid
* instruction
+ *
+ * TODO: move some of the "CF" items in here for better performance (the
+ * code-flow analysis sometimes has to process the same instruction several
+ * times).
*/
static bool verifyInstructions(const Method* meth, InsnFlags* insnFlags,
int verifyFlags)
@@ -678,6 +845,22 @@
/* plain no-op or switch table data; nothing to do here */
break;
+ case OP_CONST_STRING:
+ case OP_CONST_STRING_JUMBO:
+ if (!checkStringIndex(meth, i))
+ return false;
+ break;
+
+ case OP_CONST_CLASS:
+ case OP_CHECK_CAST:
+ if (!checkTypeIndex(meth, i, true))
+ return false;
+ break;
+ case OP_INSTANCE_OF:
+ if (!checkTypeIndex(meth, i, false))
+ return false;
+ break;
+
case OP_PACKED_SWITCH:
case OP_SPARSE_SWITCH:
/* verify the associated table */
@@ -690,7 +873,7 @@
if (!checkArrayData(meth, i))
return false;
break;
-
+
case OP_GOTO:
case OP_GOTO_16:
case OP_IF_EQ:
@@ -725,6 +908,67 @@
return false;
break;
+ case OP_FILLED_NEW_ARRAY:
+ if (!checkTypeIndex(meth, i, false))
+ return false;
+ break;
+ case OP_FILLED_NEW_ARRAY_RANGE:
+ if (!checkTypeIndex(meth, i, true))
+ return false;
+ break;
+
+ case OP_IGET:
+ case OP_IGET_WIDE:
+ case OP_IGET_OBJECT:
+ case OP_IGET_BOOLEAN:
+ case OP_IGET_BYTE:
+ case OP_IGET_CHAR:
+ case OP_IGET_SHORT:
+ case OP_IPUT:
+ case OP_IPUT_WIDE:
+ case OP_IPUT_OBJECT:
+ case OP_IPUT_BOOLEAN:
+ case OP_IPUT_BYTE:
+ case OP_IPUT_CHAR:
+ case OP_IPUT_SHORT:
+ /* check the field index */
+ if (!checkFieldIndex(meth, i, false))
+ return false;
+ break;
+ case OP_SGET:
+ case OP_SGET_WIDE:
+ case OP_SGET_OBJECT:
+ case OP_SGET_BOOLEAN:
+ case OP_SGET_BYTE:
+ case OP_SGET_CHAR:
+ case OP_SGET_SHORT:
+ case OP_SPUT:
+ case OP_SPUT_WIDE:
+ case OP_SPUT_OBJECT:
+ case OP_SPUT_BOOLEAN:
+ case OP_SPUT_BYTE:
+ case OP_SPUT_CHAR:
+ case OP_SPUT_SHORT:
+ /* check the field index */
+ if (!checkFieldIndex(meth, i, true))
+ return false;
+ break;
+
+ case OP_INVOKE_VIRTUAL:
+ case OP_INVOKE_SUPER:
+ case OP_INVOKE_DIRECT:
+ case OP_INVOKE_STATIC:
+ case OP_INVOKE_INTERFACE:
+ case OP_INVOKE_VIRTUAL_RANGE:
+ case OP_INVOKE_SUPER_RANGE:
+ case OP_INVOKE_DIRECT_RANGE:
+ case OP_INVOKE_STATIC_RANGE:
+ case OP_INVOKE_INTERFACE_RANGE:
+ /* check the method index */
+ if (!checkMethodIndex(meth, i))
+ return false;
+ break;
+
case OP_EXECUTE_INLINE:
case OP_INVOKE_DIRECT_EMPTY:
case OP_IGET_QUICK:
@@ -763,61 +1007,3 @@
return true;
}
-
-/*
- * Perform static checks on a "new-instance" instruction. Specifically,
- * make sure the class reference isn't for an array class.
- *
- * We don't need the actual class, just a pointer to the class name.
- */
-static bool checkNewInstance(const Method* meth, int insnIdx)
-{
- DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile;
- DecodedInstruction decInsn;
- const char* classDescriptor;
-
- dexDecodeInstruction(gDvm.instrFormat, meth->insns + insnIdx, &decInsn);
- classDescriptor = dexStringByTypeIdx(pDexFile, decInsn.vB); // 2nd item
-
- if (classDescriptor[0] != 'L') {
- LOG_VFY_METH(meth, "VFY: can't call new-instance on type '%s'\n",
- classDescriptor);
- return false;
- }
-
- return true;
-}
-
-/*
- * Perform static checks on a "new-array" instruction. Specifically, make
- * sure they aren't creating an array of arrays that causes the number of
- * dimensions to exceed 255.
- */
-static bool checkNewArray(const Method* meth, int insnIdx)
-{
- DexFile* pDexFile = meth->clazz->pDvmDex->pDexFile;
- DecodedInstruction decInsn;
- const char* classDescriptor;
-
- dexDecodeInstruction(gDvm.instrFormat, meth->insns + insnIdx, &decInsn);
- classDescriptor = dexStringByTypeIdx(pDexFile, decInsn.vC); // 3rd item
-
- int bracketCount = 0;
- const char* cp = classDescriptor;
- while (*cp++ == '[')
- bracketCount++;
-
- if (bracketCount == 0) {
- /* The given class must be an array type. */
- LOG_VFY_METH(meth, "VFY: can't new-array class '%s' (not an array)\n",
- classDescriptor);
- return false;
- } else if (bracketCount > 255) {
- /* It is illegal to create an array of more than 255 dimensions. */
- LOG_VFY_METH(meth, "VFY: can't new-array class '%s' (exceeds limit)\n",
- classDescriptor);
- return false;
- }
-
- return true;
-}