/* Returns the object pointer for a field
 * - obj only used if the field is not static
 * - Note: will not return an array object
 */
Object* getObjectFromField(Field* field, Object* obj)
{
    if (field->signature[0] != 'L') {
	return NULL;
    }

    if (dvmIsStaticField(field)) {
	StaticField* sfield = (StaticField*) field;
	return dvmGetStaticFieldObject(sfield);
    } else {
	InstField* ifield = (InstField*) field;
	return dvmGetFieldObject(obj, ifield->byteOffset);
    }
}
Example #2
0
/*
 * Convert a field pointer to a slot number.
 *
 * We use positive values starting from 0 for instance fields, negative
 * values starting from -1 for static fields.
 */
static int fieldToSlot(const Field* field, const ClassObject* clazz)
{
    int slot;

    if (dvmIsStaticField(field)) {
        slot = (StaticField*)field - &clazz->sfields[0];
        assert(slot >= 0 && slot < clazz->sfieldCount);
        slot = -(slot+1);
    } else {
        slot = (InstField*)field - clazz->ifields;
        assert(slot >= 0 && slot < clazz->ifieldCount);
    }

    return slot;
}
/* add tag to a field
 * - obj only used if the field is not static
 */
void addTaintToField(Field* field, Object* obj, u4 tag)
{
    if (dvmIsStaticField(field)) {
	StaticField* sfield = (StaticField*) field;
	tag |= dvmGetStaticFieldTaint(sfield);
	dvmSetStaticFieldTaint(sfield, tag);
    } else {
	InstField* ifield = (InstField*) field;
	if (field->signature[0] == 'J' || field->signature[0] == 'D') {
	    tag |= dvmGetFieldTaintWide(obj, ifield->byteOffset);
	    dvmSetFieldTaintWide(obj, ifield->byteOffset, tag);
	} else {
	    tag |= dvmGetFieldTaint(obj, ifield->byteOffset);
	    dvmSetFieldTaint(obj, ifield->byteOffset, tag);
	}
    }
}
/* Returns the taint tag for a field
 * - obj only used if the field is not static
 */
u4 getTaintFromField(Field* field, Object* obj)
{
    u4 tag = TAINT_CLEAR;

    if (dvmIsStaticField(field)) {
		StaticField* sfield = (StaticField*) field;
		tag = dvmGetStaticFieldTaint(sfield);
    } else {
	InstField* ifield = (InstField*) field;
	if (field->signature[0] == 'J' || field->signature[0] == 'D') {
	    tag = dvmGetFieldTaintWide(obj, ifield->byteOffset);
	} else {
	    tag = dvmGetFieldTaint(obj, ifield->byteOffset);
	}
    }

    return tag;
}
Example #5
0
/*
 * Alternate version of dvmResolveStaticField().
 *
 * Does not force initialization of the resolved field's class.
 *
 * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
 */
StaticField* dvmOptResolveStaticField(ClassObject* referrer, u4 sfieldIdx,
    VerifyError* pFailure)
{
    DvmDex* pDvmDex = referrer->pDvmDex;
    StaticField* resField;

    resField = (StaticField*)dvmDexGetResolvedField(pDvmDex, sfieldIdx);
    if (resField == NULL) {
        const DexFieldId* pFieldId;
        ClassObject* resClass;

        pFieldId = dexGetFieldId(pDvmDex->pDexFile, sfieldIdx);

        /*
         * Find the field's class.
         */
        resClass = dvmOptResolveClass(referrer, pFieldId->classIdx, pFailure);
        if (resClass == NULL) {
            //dvmClearOptException(dvmThreadSelf());
            assert(!dvmCheckException(dvmThreadSelf()));
            if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); }
            return NULL;
        }

        const char* fieldName =
            dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx);

        resField = (StaticField*)dvmFindFieldHier(resClass, fieldName,
                    dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->typeIdx));
        if (resField == NULL) {
            ALOGD("DexOpt: couldn't find static field %s.%s",
                resClass->descriptor, fieldName);
            if (pFailure != NULL)
                *pFailure = VERIFY_ERROR_NO_FIELD;
            return NULL;
        }
        if (!dvmIsStaticField(resField)) {
            ALOGD("DexOpt: wanted static, got instance for field %s.%s",
                resClass->descriptor, fieldName);
            if (pFailure != NULL)
                *pFailure = VERIFY_ERROR_CLASS_CHANGE;
            return NULL;
        }

        /*
         * Add it to the resolved table so we're faster on the next lookup.
         *
         * We can only do this if we're in "dexopt", because the presence
         * of a valid value in the resolution table implies that the class
         * containing the static field has been initialized.
         */
        if (gDvm.optimizing)
            dvmDexSetResolvedField(pDvmDex, sfieldIdx, (Field*) resField);
    }

    /* access allowed? */
    tweakLoader(referrer, resField->clazz);
    bool allowed = dvmCheckFieldAccess(referrer, (Field*)resField);
    untweakLoader(referrer, resField->clazz);
    if (!allowed) {
        ALOGI("DexOpt: access denied from %s to field %s.%s",
            referrer->descriptor, resField->clazz->descriptor,
            resField->name);
        if (pFailure != NULL)
            *pFailure = VERIFY_ERROR_ACCESS_FIELD;
        return NULL;
    }

    return resField;
}
/*
 * Get the address of a field from an object.  This can be used with "get"
 * or "set".
 *
 * "declaringClass" is the class in which the field was declared.  For an
 * instance field, "obj" is the object that holds the field data; for a
 * static field its value is ignored.
 *
 * "If the underlying field is static, the class that declared the
 * field is initialized if it has not already been initialized."
 *
 * On failure, throws an exception and returns NULL.
 *
 * The documentation lists exceptional conditions and the exceptions that
 * should be thrown, but doesn't say which exception previals when two or
 * more exceptional conditions exist at the same time.  For example,
 * attempting to set a protected field from an unrelated class causes an
 * IllegalAccessException, while passing in a data type that doesn't match
 * the field causes an IllegalArgumentException.  If code does both at the
 * same time, we have to choose one or othe other.
 *
 * The expected order is:
 *  (1) Check for illegal access. Throw IllegalAccessException.
 *  (2) Make sure the object actually has the field.  Throw
 *      IllegalArgumentException.
 *  (3) Make sure the field matches the expected type, e.g. if we issued
 *      a "getInteger" call make sure the field is an integer or can be
 *      converted to an int with a widening conversion.  Throw
 *      IllegalArgumentException.
 *  (4) Make sure "obj" is not null.  Throw NullPointerException.
 *
 * TODO: we're currently handling #3 after #4, because we don't check the
 * widening conversion until we're actually extracting the value from the
 * object (which won't work well if it's a null reference).
 */
static JValue* getFieldDataAddr(Object* obj, ClassObject* declaringClass,
                                int slot, bool isSetOperation, bool noAccessCheck)
{
    Field* field;
    JValue* result;

    field = dvmSlotToField(declaringClass, slot);
    assert(field != NULL);

    /* verify access */
    if (!noAccessCheck) {
        if (isSetOperation && dvmIsFinalField(field)) {
            dvmThrowException("Ljava/lang/IllegalAccessException;",
                              "field is marked 'final'");
            return NULL;
        }

        ClassObject* callerClass =
            dvmGetCaller2Class(dvmThreadSelf()->curFrame);

        /*
         * We need to check two things:
         *  (1) Would an instance of the calling class have access to the field?
         *  (2) If the field is "protected", is the object an instance of the
         *      calling class, or is the field's declaring class in the same
         *      package as the calling class?
         *
         * #1 is basic access control.  #2 ensures that, just because
         * you're a subclass of Foo, you can't mess with protected fields
         * in arbitrary Foo objects from other packages.
         */
        if (!dvmCheckFieldAccess(callerClass, field)) {
            dvmThrowException("Ljava/lang/IllegalAccessException;",
                              "access to field not allowed");
            return NULL;
        }
        if (dvmIsProtectedField(field)) {
            bool isInstance, samePackage;

            if (obj != NULL)
                isInstance = dvmInstanceof(obj->clazz, callerClass);
            else
                isInstance = false;
            samePackage = dvmInSamePackage(declaringClass, callerClass);

            if (!isInstance && !samePackage) {
                dvmThrowException("Ljava/lang/IllegalAccessException;",
                                  "access to protected field not allowed");
                return NULL;
            }
        }
    }

    if (dvmIsStaticField(field)) {
        /* init class if necessary, then return ptr to storage in "field" */
        if (!dvmIsClassInitialized(declaringClass)) {
            if (!dvmInitClass(declaringClass)) {
                assert(dvmCheckException(dvmThreadSelf()));
                return NULL;
            }
        }

        result = dvmStaticFieldPtr((StaticField*) field);
    } else {
        /*
         * Verify object is of correct type (i.e. it actually has the
         * expected field in it), then grab a pointer to obj storage.
         * The call to dvmVerifyObjectInClass throws an NPE if "obj" is NULL.
         */
        if (!dvmVerifyObjectInClass(obj, declaringClass)) {
            assert(dvmCheckException(dvmThreadSelf()));
            if (obj != NULL) {
                LOGD("Wrong type of object for field lookup: %s %s\n",
                     obj->clazz->descriptor, declaringClass->descriptor);
            }
            return NULL;
        }
        result = dvmFieldPtr(obj, ((InstField*) field)->byteOffset);
    }

    return result;
}
Example #7
0
/*
 * Alternate version of dvmResolveInstField().
 *
 * On failure, returns NULL, and sets *pFailure if pFailure is not NULL.
 */
InstField* dvmOptResolveInstField(ClassObject* referrer, u4 ifieldIdx,
    VerifyError* pFailure)
{
    DvmDex* pDvmDex = referrer->pDvmDex;
    InstField* resField;

    resField = (InstField*) dvmDexGetResolvedField(pDvmDex, ifieldIdx);
    if (resField == NULL) {
        const DexFieldId* pFieldId;
        ClassObject* resClass;

        pFieldId = dexGetFieldId(pDvmDex->pDexFile, ifieldIdx);

        /*
         * Find the field's class.
         */
        resClass = dvmOptResolveClass(referrer, pFieldId->classIdx, pFailure);
        if (resClass == NULL) {
            //dvmClearOptException(dvmThreadSelf());
            assert(!dvmCheckException(dvmThreadSelf()));
            if (pFailure != NULL) { assert(!VERIFY_OK(*pFailure)); }
            return NULL;
        }

        resField = (InstField*)dvmFindFieldHier(resClass,
            dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx),
            dexStringByTypeIdx(pDvmDex->pDexFile, pFieldId->typeIdx));
        if (resField == NULL) {
            ALOGD("DexOpt: couldn't find field %s.%s",
                resClass->descriptor,
                dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx));
            if (pFailure != NULL)
                *pFailure = VERIFY_ERROR_NO_FIELD;
            return NULL;
        }
        if (dvmIsStaticField(resField)) {
            ALOGD("DexOpt: wanted instance, got static for field %s.%s",
                resClass->descriptor,
                dexStringById(pDvmDex->pDexFile, pFieldId->nameIdx));
            if (pFailure != NULL)
                *pFailure = VERIFY_ERROR_CLASS_CHANGE;
            return NULL;
        }

        /*
         * Add it to the resolved table so we're faster on the next lookup.
         */
        dvmDexSetResolvedField(pDvmDex, ifieldIdx, (Field*) resField);
    }

    /* access allowed? */
    tweakLoader(referrer, resField->clazz);
    bool allowed = dvmCheckFieldAccess(referrer, (Field*)resField);
    untweakLoader(referrer, resField->clazz);
    if (!allowed) {
        ALOGI("DexOpt: access denied from %s to field %s.%s",
            referrer->descriptor, resField->clazz->descriptor,
            resField->name);
        if (pFailure != NULL)
            *pFailure = VERIFY_ERROR_ACCESS_FIELD;
        return NULL;
    }

    return resField;
}
/*
 * Primitive field setters, e.g.:
 * private void setIField(Object o, Class declaringClass,
 *     Class type, int slot, boolean noAccessCheck, int type_no, int value)
 *
 * The "type_no" is defined by the java.lang.reflect.Field class.
 */
static void Dalvik_java_lang_reflect_Field_setPrimitiveField(const u4* args,
    JValue* pResult)
{
    // ignore thisPtr in args[0]
    Object* obj = (Object*) args[1];
    ClassObject* declaringClass = (ClassObject*) args[2];
    ClassObject* fieldType = (ClassObject*) args[3];
    int slot = args[4];
    bool noAccessCheck = (args[5] != 0);
    int typeNum = args[6];
    const s4* valuePtr = (s4*) &args[7];
#ifdef WITH_TAINT_TRACKING
    /* rtaint = args[8]
     * thisPtr taint = args[9]
     * obj taint = args[10]
     * declaringClass taint = args[11]
     * fieldType taint = args[12]
     * slot taint = args[13]
     * noAccessCheck taint = args[14]
     * typeNum taint = args[15]
     */
    u4 valueTaint = args[16];
#endif
    PrimitiveType srcType = convPrimType(typeNum);
    JValue* fieldPtr;
    JValue value;

    if (!dvmIsPrimitiveClass(fieldType)) {
        dvmThrowException("Ljava/lang/IllegalArgumentException;",
            "not a primitive field");
        RETURN_VOID();
    }

    /* convert the 32/64-bit arg to a JValue matching the field type */
    if (dvmConvertPrimitiveValue(srcType, fieldType->primitiveType,
        valuePtr, &(value.i)) < 0)
    {
        dvmThrowException("Ljava/lang/IllegalArgumentException;",
            "invalid primitive conversion");
        RETURN_VOID();
    }

    /* get a pointer to the field's data; performs access checks */
    fieldPtr = getFieldDataAddr(obj, declaringClass, slot, true, noAccessCheck);
    if (fieldPtr == NULL)
        RETURN_VOID();

    /* store 4 or 8 bytes */
    if (fieldType->primitiveType == PRIM_LONG ||
        fieldType->primitiveType == PRIM_DOUBLE)
    {
        fieldPtr->j = value.j;
    } else {
        fieldPtr->i = value.i;
    }

#ifdef WITH_TAINT_TRACKING
    /* If we got this far, we know the fields is okay to access and there
     * will not be a problem getting the field from the slot */
    {
	Field* field = dvmSlotToField(declaringClass, slot);
	assert(field != NULL);
	if (dvmIsStaticField(field)) {
	    StaticField* sfield = (StaticField*)field;
	    dvmSetStaticFieldTaint(sfield, valueTaint);
	} else {
	    /* Note, getFieldDataAddr() already checked that
	     * obj is of type declaringClass, so no need to check here
	     */
	    InstField* ifield = (InstField*)field;
	    if (fieldType->primitiveType == PRIM_LONG ||
		fieldType->primitiveType == PRIM_DOUBLE) {
		dvmSetFieldTaintWide(obj, ifield->byteOffset, valueTaint);
	    } else {
		dvmSetFieldTaint(obj, ifield->byteOffset, valueTaint);
	    }
	}
    }
#endif

    RETURN_VOID();
}
/*
 * Primitive field getters, e.g.:
 * private double getIField(Object o, Class declaringClass,
 *     Class type, int slot, boolean noAccessCheck, int type_no)
 *
 * The "type_no" is defined by the java.lang.reflect.Field class.
 */
static void Dalvik_java_lang_reflect_Field_getPrimitiveField(const u4* args,
    JValue* pResult)
{
    // ignore thisPtr in args[0]
    Object* obj = (Object*) args[1];
    ClassObject* declaringClass = (ClassObject*) args[2];
    ClassObject* fieldType = (ClassObject*) args[3];
    int slot = args[4];
    bool noAccessCheck = (args[5] != 0);
    int typeNum = args[6];
#ifdef WITH_TAINT_TRACKING
    u4* rtaint = (u4*) &args[7]; /* return taint tag slot */
#endif
    PrimitiveType targetType = convPrimType(typeNum);
    const JValue* fieldPtr;
    JValue value;

    if (!dvmIsPrimitiveClass(fieldType)) {
        dvmThrowException("Ljava/lang/IllegalArgumentException;",
            "not a primitive field");
        RETURN_VOID();
    }

    /* get a pointer to the field's data; performs access checks */
    fieldPtr = getFieldDataAddr(obj, declaringClass, slot, false,noAccessCheck);
    if (fieldPtr == NULL)
        RETURN_VOID();

    /* copy 4 or 8 bytes out */
    if (fieldType->primitiveType == PRIM_LONG ||
        fieldType->primitiveType == PRIM_DOUBLE)
    {
        value.j = fieldPtr->j;
    } else {
        value.i = fieldPtr->i;
    }

    /* retrieve value, performing a widening conversion if necessary */
    if (dvmConvertPrimitiveValue(fieldType->primitiveType, targetType,
        &(value.i), &(pResult->i)) < 0)
    {
        dvmThrowException("Ljava/lang/IllegalArgumentException;",
            "invalid primitive conversion");
        RETURN_VOID();
    }

#ifdef WITH_TAINT_TRACKING
    /* If we got this far, we know the fields is okay to access and there
     * will not be a problem getting the field from the slot */
    {
	Field* field = dvmSlotToField(declaringClass, slot);
	assert(field != NULL);
	if (dvmIsStaticField(field)) {
	    StaticField* sfield = (StaticField*)field;
	    *rtaint = dvmGetStaticFieldTaint(sfield);
	} else {
	    /* Note, getFieldDataAddr() already checked that
	     * obj is of type declaringClass, so no need to check here
	     */
	    InstField* ifield = (InstField*)field;
	    if (fieldType->primitiveType == PRIM_LONG ||
		fieldType->primitiveType == PRIM_DOUBLE) {
		*rtaint = dvmGetFieldTaintWide(obj, ifield->byteOffset);
	    } else {
		*rtaint = dvmGetFieldTaint(obj, ifield->byteOffset);
	    }
	}
    }
#endif
}
/*
 * private void setField(Object o, Class declaringClass, Class type,
 *     int slot, boolean noAccessCheck, Object value)
 *
 * When assigning into a primitive field we will automatically extract
 * the value from box types.
 */
static void Dalvik_java_lang_reflect_Field_setField(const u4* args,
    JValue* pResult)
{
    // ignore thisPtr in args[0]
    Object* obj = (Object*) args[1];
    ClassObject* declaringClass = (ClassObject*) args[2];
    ClassObject* fieldType = (ClassObject*) args[3];
    int slot = args[4];
    bool noAccessCheck = (args[5] != 0);
    Object* valueObj = (Object*) args[6];
#ifdef WITH_TAINT_TRACKING
    /* rtaint = args[7]
     * thisPtr taint = args[8]
     * obj taint = args[9]
     * declaringClass taint = args[10]
     * fieldType taint = args[11]
     * slot taint = args[12]
     * noAccessCheck taint = args[13]
     */
    u4 valueTaint = args[14];
#endif
    JValue* fieldPtr;
    JValue value;

    /* unwrap primitive, or verify object type */
    if (!dvmUnwrapPrimitive(valueObj, fieldType, &value)) {
        dvmThrowException("Ljava/lang/IllegalArgumentException;",
            "invalid value for field");
        RETURN_VOID();
    }

    /* get a pointer to the field's data; performs access checks */
    fieldPtr = getFieldDataAddr(obj, declaringClass, slot, true, noAccessCheck);
    if (fieldPtr == NULL)
        RETURN_VOID();

    /* store 4 or 8 bytes */
    if (fieldType->primitiveType == PRIM_LONG ||
        fieldType->primitiveType == PRIM_DOUBLE)
    {
        fieldPtr->j = value.j;
    } else if (fieldType->primitiveType == PRIM_NOT) {
        if (slot < 0) {
            StaticField *sfield;
            sfield = (StaticField *)dvmSlotToField(declaringClass, slot);
            assert(fieldPtr == &sfield->value);
            dvmSetStaticFieldObject(sfield, value.l);
        } else {
            int offset = declaringClass->ifields[slot].byteOffset;
            assert(fieldPtr == (JValue *)BYTE_OFFSET(obj, offset));
            dvmSetFieldObject(obj, offset, value.l);
        }
    } else {
        fieldPtr->i = value.i;
    }

#ifdef WITH_TAINT_TRACKING
    /* If we got this far, we know the fields is okay to access and there
     * will not be a problem getting the field from the slot */
    {
	Field* field = dvmSlotToField(declaringClass, slot);
	assert(field != NULL);
	if (dvmIsStaticField(field)) {
	    StaticField* sfield = (StaticField*)field;
	    dvmSetStaticFieldTaint(sfield, valueTaint);
	} else {
	    /* Note, getFieldDataAddr() already checked that
	     * obj is of type declaringClass, so no need to check here
	     */
	    InstField* ifield = (InstField*)field;
	    if (fieldType->primitiveType == PRIM_LONG ||
		fieldType->primitiveType == PRIM_DOUBLE) {
		dvmSetFieldTaintWide(obj, ifield->byteOffset, valueTaint);
	    } else {
		dvmSetFieldTaint(obj, ifield->byteOffset, valueTaint);
	    }
	}
    }
#endif

    RETURN_VOID();
}
/*
 * private Object getField(Object o, Class declaringClass, Class type,
 *     int slot, boolean noAccessCheck)
 *
 * Primitive types need to be boxed.
 */
static void Dalvik_java_lang_reflect_Field_getField(const u4* args,
    JValue* pResult)
{
    // ignore thisPtr in args[0]
    Object* obj = (Object*) args[1];
    ClassObject* declaringClass = (ClassObject*) args[2];
    ClassObject* fieldType = (ClassObject*) args[3];
    int slot = args[4];
    bool noAccessCheck = (args[5] != 0);
#ifdef WITH_TAINT_TRACKING
    u4* rtaint = (u4*) &args[6]; /* return taint tag slot */
#endif
    JValue value;
    const JValue* fieldPtr;
    DataObject* result;

    //dvmDumpClass(obj->clazz, kDumpClassFullDetail);

    /* get a pointer to the field's data; performs access checks */
    fieldPtr = getFieldDataAddr(obj, declaringClass, slot, false,noAccessCheck);
    if (fieldPtr == NULL)
        RETURN_VOID();

    /* copy 4 or 8 bytes out */
    if (fieldType->primitiveType == PRIM_LONG ||
        fieldType->primitiveType == PRIM_DOUBLE)
    {
        value.j = fieldPtr->j;
    } else {
        value.i = fieldPtr->i;
    }

    result = dvmWrapPrimitive(value, fieldType);
    dvmReleaseTrackedAlloc((Object*) result, NULL);

#ifdef WITH_TAINT_TRACKING
    /* If we got this far, we know the fields is okay to access and there
     * will not be a problem getting the field from the slot */
    {
	Field* field = dvmSlotToField(declaringClass, slot);
	assert(field != NULL);
	if (dvmIsStaticField(field)) {
	    StaticField* sfield = (StaticField*)field;
	    *rtaint = dvmGetStaticFieldTaint(sfield);
	} else {
	    /* Note, getFieldDataAddr() already checked that
	     * obj is of type declaringClass, so no need to check here
	     */
	    InstField* ifield = (InstField*)field;
	    if (fieldType->primitiveType == PRIM_LONG ||
		fieldType->primitiveType == PRIM_DOUBLE) {
		*rtaint = dvmGetFieldTaintWide(obj, ifield->byteOffset);
	    } else {
		*rtaint = dvmGetFieldTaint(obj, ifield->byteOffset);
	    }
	}
    }
#endif

    RETURN_PTR(result);
}