8177146: MethodHandles.Lookup::bind allows illegal protected access
Reviewed-by: psandoz, vlivanov, redestad
This commit is contained in:
parent
4400cbde3b
commit
b8116f74c0
jdk
src/java.base/share/classes/java/lang/invoke
test/java/lang/invoke/8177146
@ -1691,7 +1691,13 @@ return mh1;
|
||||
public MethodHandle bind(Object receiver, String name, MethodType type) throws NoSuchMethodException, IllegalAccessException {
|
||||
Class<? extends Object> refc = receiver.getClass(); // may get NPE
|
||||
MemberName method = resolveOrFail(REF_invokeSpecial, refc, name, type);
|
||||
MethodHandle mh = getDirectMethodNoRestrict(REF_invokeSpecial, refc, method, findBoundCallerClass(method));
|
||||
MethodHandle mh = getDirectMethodNoRestrictInvokeSpecial(refc, method, findBoundCallerClass(method));
|
||||
if (!mh.type().leadingReferenceParameter().isAssignableFrom(receiver.getClass())) {
|
||||
throw new IllegalAccessException("The restricted defining class " +
|
||||
mh.type().leadingReferenceParameter().getName() +
|
||||
" is not assignable from receiver class " +
|
||||
receiver.getClass().getName());
|
||||
}
|
||||
return mh.bindArgumentL(0, receiver).setVarargs(method);
|
||||
}
|
||||
|
||||
@ -2240,7 +2246,7 @@ return mh1;
|
||||
throw method.makeAccessException("caller class must be a subclass below the method", caller);
|
||||
}
|
||||
MethodType rawType = mh.type();
|
||||
if (rawType.parameterType(0) == caller) return mh;
|
||||
if (caller.isAssignableFrom(rawType.parameterType(0))) return mh; // no need to restrict; already narrow
|
||||
MethodType narrowType = rawType.changeParameterType(0, caller);
|
||||
assert(!mh.isVarargsCollector()); // viewAsType will lose varargs-ness
|
||||
assert(mh.viewAsTypeChecks(narrowType, true));
|
||||
@ -2253,11 +2259,11 @@ return mh1;
|
||||
final boolean checkSecurity = true;
|
||||
return getDirectMethodCommon(refKind, refc, method, checkSecurity, doRestrict, callerClass);
|
||||
}
|
||||
/** Check access and get the requested method, eliding receiver narrowing rules. */
|
||||
private MethodHandle getDirectMethodNoRestrict(byte refKind, Class<?> refc, MemberName method, Class<?> callerClass) throws IllegalAccessException {
|
||||
/** Check access and get the requested method, for invokespecial with no restriction on the application of narrowing rules. */
|
||||
private MethodHandle getDirectMethodNoRestrictInvokeSpecial(Class<?> refc, MemberName method, Class<?> callerClass) throws IllegalAccessException {
|
||||
final boolean doRestrict = false;
|
||||
final boolean checkSecurity = true;
|
||||
return getDirectMethodCommon(refKind, refc, method, checkSecurity, doRestrict, callerClass);
|
||||
return getDirectMethodCommon(REF_invokeSpecial, refc, method, checkSecurity, doRestrict, callerClass);
|
||||
}
|
||||
/** Check access and get the requested method, eliding security manager checks. */
|
||||
private MethodHandle getDirectMethodNoSecurityManager(byte refKind, Class<?> refc, MemberName method, Class<?> callerClass) throws IllegalAccessException {
|
||||
@ -2309,10 +2315,8 @@ return mh1;
|
||||
DirectMethodHandle dmh = DirectMethodHandle.make(refKind, refc, method);
|
||||
MethodHandle mh = dmh;
|
||||
// Optionally narrow the receiver argument to refc using restrictReceiver.
|
||||
if (doRestrict &&
|
||||
(refKind == REF_invokeSpecial ||
|
||||
(MethodHandleNatives.refKindHasReceiver(refKind) &&
|
||||
restrictProtectedReceiver(method)))) {
|
||||
if ((doRestrict && refKind == REF_invokeSpecial) ||
|
||||
(MethodHandleNatives.refKindHasReceiver(refKind) && restrictProtectedReceiver(method))) {
|
||||
mh = restrictReceiver(method, dmh, lookupClass());
|
||||
}
|
||||
mh = maybeBindCaller(method, mh, callerClass);
|
||||
|
96
jdk/test/java/lang/invoke/8177146/TestMethodHandleBind.java
Normal file
96
jdk/test/java/lang/invoke/8177146/TestMethodHandleBind.java
Normal file
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/* @test
|
||||
* @bug 8177146
|
||||
* @run testng/othervm TestMethodHandleBind
|
||||
*/
|
||||
|
||||
import org.testng.annotations.Test;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodType;
|
||||
|
||||
import static java.lang.invoke.MethodHandles.lookup;
|
||||
|
||||
import static org.testng.Assert.*;
|
||||
|
||||
public class TestMethodHandleBind extends pkg.A {
|
||||
static class B extends TestMethodHandleBind {}
|
||||
|
||||
@Test
|
||||
public void testInstanceOfCallerClass() throws Throwable {
|
||||
MethodHandle bound = lookup().bind(new TestMethodHandleBind() , "m1", MethodType.methodType(String.class));
|
||||
String x = (String)bound.invoke();
|
||||
assertEquals(x, this.getClass().getSimpleName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInstanceOfCallerSubclass() throws Throwable {
|
||||
MethodHandle bound = lookup().bind(new B() , "m1", MethodType.methodType(String.class));
|
||||
// MethodHandle bound = lookup().findVirtual(B.class, "m1", MethodType.methodType(String.class)).bindTo(new B());
|
||||
String x = (String)bound.invoke();
|
||||
assertEquals(x, "B");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInstanceOfReceiverClass() throws Throwable {
|
||||
try {
|
||||
MethodHandle bound = lookup().bind(new pkg.A() , "m1", MethodType.methodType(String.class));
|
||||
bound.invoke();
|
||||
fail("IllegalAccessException expected");
|
||||
} catch (IllegalAccessException e) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPublicMethod() throws Throwable {
|
||||
MethodHandle bound = lookup().bind(new pkg.A() , "m2", MethodType.methodType(String.class));
|
||||
String x = (String)bound.invoke();
|
||||
assertEquals(x, "A");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPublicMethod2() throws Throwable {
|
||||
MethodHandle bound = lookup().bind(new TestMethodHandleBind(), "m2", MethodType.methodType(String.class));
|
||||
String x = (String)bound.invoke();
|
||||
assertEquals(x, this.getClass().getSimpleName());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInstanceOfCallerClassVarargs() throws Throwable {
|
||||
MethodHandle bound = lookup().bind(new TestMethodHandleBind() , "m3", MethodType.methodType(String.class, String[].class));
|
||||
String x = (String)bound.invoke("a", "b", "c");
|
||||
assertEquals(x, this.getClass().getSimpleName() + "abc");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInstanceOfReceiverClassVarargs() throws Throwable {
|
||||
try {
|
||||
MethodHandle bound = lookup().bind(new pkg.A(), "m3", MethodType.methodType(String.class, String[].class));
|
||||
bound.invoke();
|
||||
fail("IllegalAccessException expected");
|
||||
} catch (IllegalAccessException e) {
|
||||
}
|
||||
}
|
||||
}
|
40
jdk/test/java/lang/invoke/8177146/pkg/A.java
Normal file
40
jdk/test/java/lang/invoke/8177146/pkg/A.java
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 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
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||
* or visit www.oracle.com if you need additional information or have any
|
||||
* questions.
|
||||
*/
|
||||
package pkg;
|
||||
|
||||
public class A {
|
||||
protected String m1() {
|
||||
return this.getClass().getSimpleName();
|
||||
}
|
||||
|
||||
public String m2() {
|
||||
return this.getClass().getSimpleName();
|
||||
}
|
||||
|
||||
protected String m3(String... args) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (String s : args)
|
||||
sb.append(s);
|
||||
return this.getClass().getSimpleName() + sb.toString();
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user