8160987: JDWP ClassType.InvokeMethod doesn't validate class
Add code to validate class in JDWP instead of relying on JNI to do the check. Reviewed-by: dholmes, dcubed, sspitsyn, dsamersoff
This commit is contained in:
parent
b339daff4b
commit
89744d775f
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1998, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -343,6 +343,35 @@ invoker_enableInvokeRequests(jthread thread)
|
||||
debugMonitorExit(invokerLock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check that method is in the specified clazz or one of its super classes.
|
||||
* We have to enforce this check at the JDWP layer because the JNI layer
|
||||
* has different requirements.
|
||||
*/
|
||||
static jvmtiError check_methodClass(JNIEnv *env, jclass clazz, jmethodID method)
|
||||
{
|
||||
jclass containing_class = NULL;
|
||||
jvmtiError error;
|
||||
|
||||
error = JVMTI_FUNC_PTR(gdata->jvmti,GetMethodDeclaringClass)
|
||||
(gdata->jvmti, method, &containing_class);
|
||||
if (error != JVMTI_ERROR_NONE) {
|
||||
return JVMTI_ERROR_NONE; /* Bad jmethodID ? This will be handled elsewhere */
|
||||
}
|
||||
|
||||
if (JNI_FUNC_PTR(env,IsSameObject)(env, clazz, containing_class)) {
|
||||
return JVMTI_ERROR_NONE;
|
||||
}
|
||||
|
||||
// If not the same class then check that containing_class is a superclass of
|
||||
// clazz (not a superinterface).
|
||||
if (JNI_FUNC_PTR(env,IsAssignableFrom)(env, clazz, containing_class) &&
|
||||
referenceTypeTag(containing_class) != JDWP_TYPE_TAG(INTERFACE)) {
|
||||
return JVMTI_ERROR_NONE;
|
||||
}
|
||||
return JVMTI_ERROR_INVALID_METHODID;
|
||||
}
|
||||
|
||||
jvmtiError
|
||||
invoker_requestInvoke(jbyte invokeType, jbyte options, jint id,
|
||||
jthread thread, jclass clazz, jmethodID method,
|
||||
@ -353,6 +382,13 @@ invoker_requestInvoke(jbyte invokeType, jbyte options, jint id,
|
||||
InvokeRequest *request;
|
||||
jvmtiError error = JVMTI_ERROR_NONE;
|
||||
|
||||
if (invokeType == INVOKE_STATIC) {
|
||||
error = check_methodClass(env, clazz, method);
|
||||
if (error != JVMTI_ERROR_NONE) {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
|
||||
debugMonitorEnter(invokerLock);
|
||||
request = threadControl_getInvokeRequest(thread);
|
||||
if (request != NULL) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -197,14 +197,18 @@ public class InterfaceMethodsTest extends TestScaffold {
|
||||
// invoke interface static method A
|
||||
testInvokePos(ifaceClass, null, "staticMethodA", "()I", vm().mirrorOf(RESULT_A));
|
||||
|
||||
// try to invoke static method A on the instance
|
||||
testInvokePos(ifaceClass, ref, "staticMethodA", "()I", vm().mirrorOf(RESULT_A));
|
||||
// invoking static method A on the instance fails because static method A is
|
||||
// not inherited by TargetClass.
|
||||
testInvokeNeg(ifaceClass, ref, "staticMethodA", "()I", vm().mirrorOf(RESULT_A),
|
||||
"Invalid MethodID");
|
||||
|
||||
// invoke interface static method B
|
||||
testInvokePos(ifaceClass, null, "staticMethodB", "()I", vm().mirrorOf(RESULT_A));
|
||||
|
||||
// try to invoke static method B on the instance
|
||||
testInvokePos(ifaceClass, ref, "staticMethodB", "()I", vm().mirrorOf(RESULT_A));
|
||||
// invoking static method B on the instance fails because static method B is
|
||||
// not inherited by TargetClass.
|
||||
testInvokeNeg(ifaceClass, ref, "staticMethodB", "()I", vm().mirrorOf(RESULT_A),
|
||||
"Invalid MethodID");
|
||||
|
||||
// try to invoke a virtual method
|
||||
testInvokePos(ifaceClass, ref, "implementedMethod", "()I", vm().mirrorOf(RESULT_A), true);
|
||||
@ -239,21 +243,25 @@ public class InterfaceMethodsTest extends TestScaffold {
|
||||
testInvokeNeg(ifaceClass, null, "staticMethodA", "()I", vm().mirrorOf(RESULT_A),
|
||||
"Static interface methods are not inheritable");
|
||||
|
||||
// however it is possible to call "staticMethodA" on the actual instance
|
||||
// "staticMethodA" is not inherited by InterfaceB even from an actual instance
|
||||
testInvokeNeg(ifaceClass, ref, "staticMethodA", "()I", vm().mirrorOf(RESULT_A),
|
||||
"Static interface methods are not inheritable");
|
||||
|
||||
// "staticMethodB" is overridden in InterfaceB
|
||||
// "staticMethodB" is re-defined in InterfaceB
|
||||
testInvokePos(ifaceClass, null, "staticMethodB", "()I", vm().mirrorOf(RESULT_B));
|
||||
|
||||
// the instance invokes the overriden form of "staticMethodB" from InterfaceB
|
||||
testInvokePos(ifaceClass, ref, "staticMethodB", "()I", vm().mirrorOf(RESULT_B));
|
||||
// the instance fails to invoke the re-defined form of "staticMethodB" from
|
||||
// InterfaceB because staticMethodB is not inherited by TargetClass
|
||||
testInvokeNeg(ifaceClass, ref, "staticMethodB", "()I", vm().mirrorOf(RESULT_B),
|
||||
"Invalid MethodID");
|
||||
|
||||
// "staticMethodC" is present only in InterfaceB
|
||||
testInvokePos(ifaceClass, null, "staticMethodC", "()I", vm().mirrorOf(RESULT_B));
|
||||
|
||||
// "staticMethodC" should be reachable from the instance too
|
||||
testInvokePos(ifaceClass, ref, "staticMethodC", "()I", vm().mirrorOf(RESULT_B));
|
||||
// "staticMethodC" is not reachable from the instance because staticMethodC
|
||||
// is not inherited by TargetClass.
|
||||
testInvokeNeg(ifaceClass, ref, "staticMethodC", "()I", vm().mirrorOf(RESULT_B),
|
||||
"Invalid MethodID");
|
||||
}
|
||||
|
||||
private void testImplementationClass(ReferenceType targetClass, ObjectReference thisObject) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user