/* Code called from dvmJniStartup()
 * Initializes the gPolicyTable for fast lookup of taint policy 
 * profiles for methods.
 */
void dvmTaintPropJniStartup()
{
    TaintPolicy* policy;
    u4 hash;
    
    /* Create the policy table (perfect size) */
    gPolicyTable = dvmHashTableCreate(
	    dvmHashSize(TAINT_POLICY_TABLE_SIZE), 
	    freeTaintPolicy);

    for (policy = gDvmJniTaintPolicy; policy->classDescriptor != NULL; policy++) {
	const TaintProfile *profile;
    
	/* Create the method table for this class */
	policy->methodTable = dvmHashTableCreate(
		TAINT_PROFILE_TABLE_SIZE, freeTaintProfile);

	/* Add all of the methods */
	for (profile = &policy->profiles[0]; profile->methodName != NULL; profile++) {
	    hash = dvmComputeUtf8Hash(profile->methodName);
	    dvmHashTableLookup(policy->methodTable, hash,(void *) profile,
		    hashcmpTaintProfile, true);
	}

	/* Add this class to gPolicyTable */
	hash = dvmComputeUtf8Hash(policy->classDescriptor);
	dvmHashTableLookup(gPolicyTable, hash, policy, 
		hashcmpTaintPolicy, true);
    }

#ifdef TAINT_JNI_LOG
    /* JNI logging for debugging purposes */
    gJniLogSeen = dvmHashTableCreate(dvmHashSize(50), free);
#endif
}
/* Returns the TaintPolicyProfile associated with this method
 * - returns NULL if not found
 */
TaintProfile* getPolicyProfile(const Method* method)
{
    TaintPolicy* policy = NULL;
    TaintProfile* profile = NULL;
    u4 hash;

    /* temporary variables for the search */
    TaintPolicy tPol = {NULL, NULL, NULL};
    TaintProfile tProf = {NULL, NULL};

    dvmHashTableLock(gPolicyTable);

    /* Find the class */
    hash = dvmComputeUtf8Hash(method->clazz->descriptor);
    tPol.classDescriptor = method->clazz->descriptor;
    policy = (TaintPolicy*) dvmHashTableLookup(gPolicyTable,
	    hash, &tPol, hashcmpTaintPolicy, false);

    if (policy != NULL) {
	dvmHashTableLock(policy->methodTable);

	/* Find the Method */
	hash = dvmComputeUtf8Hash(method->name);
	tProf.methodName = method->name;
	profile = (TaintProfile*) dvmHashTableLookup(policy->methodTable,
		hash, &tProf, hashcmpTaintProfile, false);

	dvmHashTableUnlock(policy->methodTable);
    }

    dvmHashTableUnlock(gPolicyTable);

    return profile;
}
/*
 * 添加特定的DexOrJar到hash表中
 */
static void addToDexFileTable(DexOrJar* pDexOrJar) {
    /*
     * Later on, we will receive this pointer as an argument and need
     * to find it in the hash table without knowing if it's valid or
     * not, which means we can't compute a hash value from anything
     * inside DexOrJar. We don't share DexOrJar structs when the same
     * file is opened multiple times, so we can just use the low 32
     * bits of the pointer as the hash.
     */
    u4 hash = (u4) pDexOrJar;
    void* result;

    dvmHashTableLock(gDvm.userDexFiles);
    /* true 代表添加  false 代表不添加*/
    result = dvmHashTableLookup(gDvm.userDexFiles, hash, pDexOrJar,
            hashcmpDexOrJar, true);
    dvmHashTableUnlock(gDvm.userDexFiles);

    if (result != pDexOrJar) {
        ALOGE("Pointer has already been added?");
        dvmAbort();
    }

    pDexOrJar->okayToFree = true;
}
Example #4
0
/*
 *查询hprof class id.
*/
hprof_class_object_id hprofLookupClassId(const ClassObject *clazz)
{
    void *val;

    if (clazz == NULL) {
        /* Someone's probably looking up the superclass
         * of java.lang.Object or of a primitive class.
         */
        return (hprof_class_object_id)0;
    }

    dvmHashTableLock(gClassHashTable);

    /* We're using the hash table as a list.
     * TODO: replace the hash table with a more suitable structure
     */
    val = dvmHashTableLookup(gClassHashTable, computeClassHash(clazz),
            (void *)clazz, classCmp, true);
    assert(val != NULL);

    dvmHashTableUnlock(gClassHashTable);

    /* Make sure that the class's name is in the string table.
     * This is a bunch of extra work that we only have to do
     * because of the order of tables in the output file
     * (strings need to be dumped before classes).
     */
    getPrettyClassNameId(clazz->descriptor);

    return (hprof_class_object_id)clazz;
}
Example #5
0
static StringObject* insertString(HashTable* table, u4 key, StringObject* value)
{
    if (dvmIsNonMovingObject(value) == false) {
        value = (StringObject*)dvmCloneObject(value, ALLOC_NON_MOVING);
    }
    void* entry = dvmHashTableLookup(table, key, (void*)value,
                                     dvmHashcmpStrings, true);
    return (StringObject*)entry;
}
Example #6
0
static Thread* lookupThreadInHash(u4 threadId) {
  Thread* result;
  dvmHashTableLock(gDvm.offThreadTable); {
    // This is a bit of a hack but whatever, it gets the job done without having
    // to allocate an entire Thread structure.
    result = (Thread*)dvmHashTableLookup(gDvm.offThreadTable, threadId,
                         ((char*)&threadId) - offsetof(Thread, threadId),
                         compareThreadData, false);
  } dvmHashTableUnlock(gDvm.offThreadTable);
  return result;
}
Example #7
0
static u4
hprofLookupStackSerialNumber(const StackTraceEntry *stackTrace)
{
    StackTraceEntry *val;
    u4 hashValue;
    int serial;

    /*
     * Create the hash table on first contact.  We can't do this in
     * hprofStartupStack, because we have to compute stack trace
     * serial numbers and place them into object headers before the
     * rest of hprof is triggered by a GC event.
     */
    if (gStackTraceHashTable == NULL) {
        gStackTraceHashTable = dvmHashTableCreate(512, free);
    }
    dvmHashTableLock(gStackTraceHashTable);

    hashValue = computeStackTraceHash(stackTrace);
    val = dvmHashTableLookup(gStackTraceHashTable, hashValue, (void *)stackTrace,
            (HashCompareFunc)stackCmp, false);
    if (val == NULL) {
        StackTraceEntry *newStackTrace;

        newStackTrace = stackDup(stackTrace);
        newStackTrace->trace.serialNumber = ++gSerialNumber;
        val = dvmHashTableLookup(gStackTraceHashTable, hashValue,
                (void *)newStackTrace, (HashCompareFunc)stackCmp, true);
        assert(val != NULL);
    }

    /* Mark the trace as live (in use by an object in the current heap). */
    val->live = 1;

    /* Grab the serial number before unlocking the table. */
    serial = val->trace.serialNumber;

    dvmHashTableUnlock(gStackTraceHashTable);

    return serial;
}
hprof_stack_frame_id
hprofLookupStackFrameId(const StackFrameEntry *stackFrameEntry)
{
    StackFrameEntry *val;
    u4 hashValue;

    /*
     * Create the hash table on first contact.  We can't do this in
     * hprofStartupStackFrame, because we have to compute stack trace
     * serial numbers and place them into object headers before the
     * rest of hprof is triggered by a GC event.
     */
    if (gStackFrameHashTable == NULL) {
        gStackFrameHashTable = dvmHashTableCreate(512, free);
    }
    dvmHashTableLock(gStackFrameHashTable);

    hashValue = computeStackFrameHash(stackFrameEntry);
    val = dvmHashTableLookup(gStackFrameHashTable, hashValue,
        (void *)stackFrameEntry, (HashCompareFunc)stackFrameCmp, false);
    if (val == NULL) {
        const StackFrameEntry *newStackFrameEntry;

        newStackFrameEntry = stackFrameDup(stackFrameEntry);
        val = dvmHashTableLookup(gStackFrameHashTable, hashValue,
            (void *)newStackFrameEntry, (HashCompareFunc)stackFrameCmp, true);
        assert(val != NULL);
    }

    /* Mark the frame as live (in use by an object in the current heap). */
    val->live = 1;

    dvmHashTableUnlock(gStackFrameHashTable);

    return (hprof_stack_frame_id) val;
}
/*
 * Verify that the "cookie" is a DEX file we opened.
 *
 * Expects that the hash table will be *unlocked* here.
 *
 * If the cookie is invalid, we throw an exception and return "false".
 */
static bool validateCookie(int cookie)
{
    DexOrJar* pDexOrJar = (DexOrJar*) cookie;

    LOGVV("+++ dex verifying cookie %p", pDexOrJar);

    if (pDexOrJar == NULL)
        return false;

    u4 hash = cookie;
    dvmHashTableLock(gDvm.userDexFiles);
    void* result = dvmHashTableLookup(gDvm.userDexFiles, hash, pDexOrJar,
                hashcmpDexOrJar, false);
    dvmHashTableUnlock(gDvm.userDexFiles);
    if (result == NULL) {
        dvmThrowRuntimeException("invalid DexFile cookie");
        return false;
    }

    return true;
}
/*
 * Verify that the "cookie" is a DEX file we opened.
 *
 * Expects that the hash table will be *unlocked* here.
 *
 * If the cookie is invalid, we throw an exception and return "false".
 */
static bool validateCookie(int cookie)
{
    DexOrJar* pDexOrJar = (DexOrJar*) cookie;

    LOGVV("+++ dex verifying cookie %p\n", pDexOrJar);

    if (pDexOrJar == NULL)
        return false;

    u4 hash = dvmComputeUtf8Hash(pDexOrJar->fileName);
    dvmHashTableLock(gDvm.userDexFiles);
    void* result = dvmHashTableLookup(gDvm.userDexFiles, hash, pDexOrJar,
                hashcmpDexOrJar, false);
    dvmHashTableUnlock(gDvm.userDexFiles);
    if (result == NULL) {
        dvmThrowException("Ljava/lang/RuntimeException;",
            "invalid DexFile cookie");
        return false;
    }

    return true;
}
/* Used to propagate taint for JNI methods
 * Two types of propagation:
 *  1) simple conservative propagation based on parameters
 *  2) propagation based on function profile policies
 */
void dvmTaintPropJniMethod(const u4* args, JValue* pResult, const Method* method, const int nativeTaint)
{
    const DexProto* proto = &method->prototype;
    DexParameterIterator pIterator;
    int nParams = dexProtoGetParameterCount(proto);
    int pStart = (dvmIsStaticMethod(method)?0:1); /* index where params start */

    /* Consider 3 arguments. [x] indicates return taint index
     * 0 1 2 [3] 4 5 6
     */
    int nArgs = method->insSize;
    u4* rtaint = (u4*) &args[nArgs]; /* The return taint value */
    int tStart = nArgs+1; /* index of args[] where taint values start */
    int tEnd   = nArgs*2; /* index of args[] where taint values end */
    u4	tag = TAINT_CLEAR;
    int i;

#if 0
    {
        char *desc = dexProtoCopyMethodDescriptor(proto);
        ALOGW("Jni: %s.%s%s, descriptor: %s", 
            method->clazz->descriptor, method->name, 
            dvmIsStaticMethod(method)?"[static]":"", desc);
        free(desc);
    }
#endif

#ifdef TAINT_JNI_LOG
    /* JNI logging for debugging purposes */
    if (gJniLog) {
	u4 hash;
	int len;
	char *inStr, *outStr;

	len = strlen(method->clazz->descriptor) + 1 + strlen(method->name);
	inStr = (char*) malloc(len+1);
	strcpy(inStr, method->clazz->descriptor);
	strcat(inStr, ".");
	strcat(inStr, method->name);
	hash = dvmComputeUtf8Hash(inStr);

	dvmHashTableLock(gJniLogSeen);

	outStr = (char*) dvmHashTableLookup(gJniLogSeen, hash, inStr, 
		(HashCompareFunc) strcmp, false);

	if (outStr == NULL) {
	    /* New method! */
	    /* add it */
	    dvmHashTableLookup(gJniLogSeen, hash, inStr, 
		(HashCompareFunc) strcmp, true);
	} else {
	    free(inStr); /* don't need this anymore */
	}

	dvmHashTableUnlock(gJniLogSeen);
    }
#endif

    /* Union the taint tags, this includes object ref tags 
     * - we don't need to worry about static vs. not static, because getting
     *	 the taint tag on the "this" object reference is a good
     * - we don't need to worry about wide registers, because the stack
     *	 interleaving of taint tags makes it transparent
     */
    /*for (i = tStart; i <= tEnd; i++) {
    	tag |= args[i];
    	if (args[i]!=0 && args[i]!=TAINT_ACCELEROMETER) //found a taint, and its not the accelerometer spam either
    		ALOGD("dvmTaintPropJNIMethod found taint %08x in method=%s:%s(%s) for arg[%d]=%08x",
    				args[i], method->clazz->descriptor, method->name, method->shorty, i-nArgs, args[i-nArgs]);
    }*/

    /* If not static, pull any taint from the "this" object */
    /*if (!dvmIsStaticMethod(method)) {
	tag |= getObjectTaint((Object*)args[0], method->clazz->descriptor);
    }*/

    /* Union taint from Objects we care about */
    dexParameterIteratorInit(&pIterator, proto);
    for (i=pStart; ; i++) {
	const char* desc = dexParameterIteratorNextDescriptor(&pIterator);

	if (desc == NULL) {
	    break;
	} 
	
	if (desc[0] == '[' || desc[0] == 'L') {
	    tag |= getObjectTaint((Object*) args[i], desc);
	}

	if (desc[0] == 'J' || desc[0] == 'D') {
	    /* wide argument, increment index one more */
	    i++;
	}
    }

    /* Look at the taint policy profiles (may have return taint) */
    //tag |= propMethodProfile(args, method);

    /* Update return taint according to the return type */
    //Native Tainting: get taint Value from native code
    //if (tag) {
    if (nativeTaint) {
	const char* desc = dexProtoGetReturnType(proto);
	//setReturnTaint(tag, rtaint, pResult, desc);
	ALOGD("dvmTaintPropJniMethod: setting result taint to %x", nativeTaint);
	setReturnTaint(nativeTaint, rtaint, pResult, desc);
    }
}
Example #12
0
static void addThreadToHash(Thread* thread) {
  dvmHashTableLock(gDvm.offThreadTable); {
    dvmHashTableLookup(gDvm.offThreadTable, thread->threadId,
                       thread, compareThreadData, true);
  } dvmHashTableUnlock(gDvm.offThreadTable);
}
Example #13
0
static StringObject* lookupString(HashTable* table, u4 key, StringObject* value)
{
    void* entry = dvmHashTableLookup(table, key, (void*)value,
                                     dvmHashcmpStrings, false);
    return (StringObject*)entry;
}
Example #14
0
/*
 * Some quick hash table tests.
 */
bool dvmTestHash()
{
    HashTable* pTab;
    char tmpStr[64];
    const char* str;
    u4 hash;
    int i;

    ALOGV("TestHash BEGIN");

    pTab = dvmHashTableCreate(dvmHashSize(12), free);
    if (pTab == NULL)
        return false;

    dvmHashTableLock(pTab);

    /* add some entries */
    for (i = 0; i < kNumTestEntries; i++) {
        sprintf(tmpStr, "entry %d", i);
        hash = dvmComputeUtf8Hash(tmpStr);
        dvmHashTableLookup(pTab, hash, strdup(tmpStr),
            (HashCompareFunc) strcmp, true);
    }

    dvmHashTableUnlock(pTab);

    /* make sure we can find all entries */
    for (i = 0; i < kNumTestEntries; i++) {
        sprintf(tmpStr, "entry %d", i);
        hash = dvmComputeUtf8Hash(tmpStr);
        str = (const char*) dvmHashTableLookup(pTab, hash, tmpStr,
                (HashCompareFunc) strcmp, false);
        if (str == NULL) {
            ALOGE("TestHash: failure: could not find '%s'", tmpStr);
            /* return false */
        }
    }

    /* make sure it behaves correctly when entry not found and !doAdd */
    sprintf(tmpStr, "entry %d", 17);
    hash = dvmComputeUtf8Hash(tmpStr);
    str = (const char*) dvmHashTableLookup(pTab, hash, tmpStr,
            (HashCompareFunc) strcmp, false);
    if (str == NULL) {
        /* good */
    } else {
        ALOGE("TestHash found nonexistent string (improper add?)");
    }

    dumpForeach(pTab);
    dumpIterator(pTab);

    /* make sure they all get freed */
    dvmHashTableFree(pTab);


    /*
     * Round 2: verify probing & tombstones.
     */
    pTab = dvmHashTableCreate(dvmHashSize(2), free);
    if (pTab == NULL)
        return false;

    hash = 0;

    /* two entries, same hash, different values */
    const char* str1;
    str1 = (char*) dvmHashTableLookup(pTab, hash, strdup("one"),
            (HashCompareFunc) strcmp, true);
    assert(str1 != NULL);
    str = (const char*) dvmHashTableLookup(pTab, hash, strdup("two"),
            (HashCompareFunc) strcmp, true);

    /* remove the first one */
    if (!dvmHashTableRemove(pTab, hash, (void*)str1))
        ALOGE("TestHash failed to delete item");
    else
        free((void*)str1);     // "Remove" doesn't call the free func

    /* make sure iterator doesn't included deleted entries */
    int count = 0;
    HashIter iter;
    for (dvmHashIterBegin(pTab, &iter); !dvmHashIterDone(&iter);
        dvmHashIterNext(&iter))
    {
        count++;
    }
    if (count != 1) {
        ALOGE("TestHash wrong number of entries (%d)", count);
    }

    /* see if we can find them */
    str = (const char*) dvmHashTableLookup(pTab, hash, (void*)"one",
            (HashCompareFunc) strcmp,false);
    if (str != NULL)
        ALOGE("TestHash deleted entry has returned!");
    str = (const char*) dvmHashTableLookup(pTab, hash, (void*)"two",
            (HashCompareFunc) strcmp,false);
    if (str == NULL)
        ALOGE("TestHash entry vanished");

    /* force a table realloc to exercise tombstone removal */
    for (i = 0; i < 20; i++) {
        sprintf(tmpStr, "entry %d", i);
        str = (const char*) dvmHashTableLookup(pTab, hash, strdup(tmpStr),
                (HashCompareFunc) strcmp, true);
        assert(str != NULL);
    }

    dvmHashTableFree(pTab);
    ALOGV("TestHash END");

    return true;
}
/*
 * private static int openDexFile(String sourceName, String outputName,
 *     int flags) throws IOException
 *
 * Open a DEX file, returning a pointer to our internal data structure.
 *
 * "sourceName" should point to the "source" jar or DEX file.
 *
 * If "outputName" is NULL, the DEX code will automatically find the
 * "optimized" version in the cache directory, creating it if necessary.
 * If it's non-NULL, the specified file will be used instead.
 *
 * TODO: at present we will happily open the same file more than once.
 * To optimize this away we could search for existing entries in the hash
 * table and refCount them.  Requires atomic ops or adding "synchronized"
 * to the non-native code that calls here.
 */
static void Dalvik_dalvik_system_DexFile_openDexFile(const u4* args,
    JValue* pResult)
{
    StringObject* sourceNameObj = (StringObject*) args[0];
    StringObject* outputNameObj = (StringObject*) args[1];
    int flags = args[2];
    DexOrJar* pDexOrJar = NULL;
    JarFile* pJarFile;
    RawDexFile* pRawDexFile;
    char* sourceName;
    char* outputName;

    if (sourceNameObj == NULL) {
        dvmThrowException("Ljava/lang/NullPointerException;", NULL);
        RETURN_VOID();
    }

    sourceName = dvmCreateCstrFromString(sourceNameObj);
    if (outputNameObj != NULL)
        outputName = dvmCreateCstrFromString(outputNameObj);
    else
        outputName = NULL;

    /*
     * We have to deal with the possibility that somebody might try to
     * open one of our bootstrap class DEX files.  The set of dependencies
     * will be different, and hence the results of optimization might be
     * different, which means we'd actually need to have two versions of
     * the optimized DEX: one that only knows about part of the boot class
     * path, and one that knows about everything in it.  The latter might
     * optimize field/method accesses based on a class that appeared later
     * in the class path.
     *
     * We can't let the user-defined class loader open it and start using
     * the classes, since the optimized form of the code skips some of
     * the method and field resolution that we would ordinarily do, and
     * we'd have the wrong semantics.
     *
     * We have to reject attempts to manually open a DEX file from the boot
     * class path.  The easiest way to do this is by filename, which works
     * out because variations in name (e.g. "/system/framework/./ext.jar")
     * result in us hitting a different dalvik-cache entry.  It's also fine
     * if the caller specifies their own output file.
     */
    if (dvmClassPathContains(gDvm.bootClassPath, sourceName)) {
        LOGW("Refusing to reopen boot DEX '%s'\n", sourceName);
        dvmThrowException("Ljava/io/IOException;",
            "Re-opening BOOTCLASSPATH DEX files is not allowed");
        free(sourceName);
        RETURN_VOID();
    }

    /*
     * Try to open it directly as a DEX.  If that fails, try it as a Zip
     * with a "classes.dex" inside.
     */
    if (dvmRawDexFileOpen(sourceName, outputName, &pRawDexFile, false) == 0) {
        LOGV("Opening DEX file '%s' (DEX)\n", sourceName);

        pDexOrJar = (DexOrJar*) malloc(sizeof(DexOrJar));
        pDexOrJar->isDex = true;
        pDexOrJar->pRawDexFile = pRawDexFile;
    } else if (dvmJarFileOpen(sourceName, outputName, &pJarFile, false) == 0) {
        LOGV("Opening DEX file '%s' (Jar)\n", sourceName);

        pDexOrJar = (DexOrJar*) malloc(sizeof(DexOrJar));
        pDexOrJar->isDex = false;
        pDexOrJar->pJarFile = pJarFile;
    } else {
        LOGV("Unable to open DEX file '%s'\n", sourceName);
        dvmThrowException("Ljava/io/IOException;", "unable to open DEX file");
    }

    if (pDexOrJar != NULL) {
        pDexOrJar->fileName = sourceName;

        /* add to hash table */
        u4 hash = dvmComputeUtf8Hash(sourceName);
        void* result;
        dvmHashTableLock(gDvm.userDexFiles);
        result = dvmHashTableLookup(gDvm.userDexFiles, hash, pDexOrJar,
                    hashcmpDexOrJar, true);
        dvmHashTableUnlock(gDvm.userDexFiles);
        if (result != pDexOrJar) {
            LOGE("Pointer has already been added?\n");
            dvmAbort();
        }

        pDexOrJar->okayToFree = true;
    } else
        free(sourceName);

    RETURN_PTR(pDexOrJar);
}