8020508: Enforce reflection access restrictions on Object.bindProperties
Reviewed-by: jlaskey, sundar
--- a/nashorn/src/jdk/nashorn/internal/objects/NativeObject.java Mon Jul 15 15:51:06 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/objects/NativeObject.java Mon Jul 15 16:31:49 2013 +0200
@@ -619,6 +619,7 @@
propertyNames.addAll(writablePropertyNames);
final Class<?> clazz = source.getClass();
+ Bootstrap.checkReflectionAccess(clazz);
final MethodType getterType = MethodType.methodType(Object.class, clazz);
final MethodType setterType = MethodType.methodType(Object.class, clazz, Object.class);
--- a/nashorn/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java Mon Jul 15 15:51:06 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java Mon Jul 15 16:31:49 2013 +0200
@@ -217,6 +217,17 @@
public static Object bindDynamicMethod(Object dynamicMethod, Object boundThis) {
return new BoundDynamicMethod(dynamicMethod, boundThis);
}
+
+ /**
+ * If the given class is a reflection-specific class (anything in {@code java.lang.reflect} and
+ * {@code java.lang.invoke} package, as well a {@link Class} and any subclass of {@link ClassLoader}) and there is
+ * a security manager in the system, then it checks the {@code nashorn.JavaReflection} {@code RuntimePermission}.
+ * @param clazz the class being tested
+ */
+ public static void checkReflectionAccess(Class<?> clazz) {
+ ReflectionCheckLinker.checkReflectionAccess(clazz);
+ }
+
/**
* Returns the Nashorn's internally used dynamic linker's services object. Note that in code that is processing a
* linking request, you will normally use the {@code LinkerServices} object passed by whatever top-level linker
--- a/nashorn/src/jdk/nashorn/internal/runtime/linker/ReflectionCheckLinker.java Mon Jul 15 15:51:06 2013 +0200
+++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/ReflectionCheckLinker.java Mon Jul 15 16:31:49 2013 +0200
@@ -40,10 +40,10 @@
final class ReflectionCheckLinker implements TypeBasedGuardingDynamicLinker{
@Override
public boolean canLinkType(final Class<?> type) {
- return canLinkTypeStatic(type);
+ return isReflectionClass(type);
}
- private static boolean canLinkTypeStatic(final Class<?> type) {
+ private static boolean isReflectionClass(final Class<?> type) {
if (type == Class.class || ClassLoader.class.isAssignableFrom(type)) {
return true;
}
@@ -54,6 +54,19 @@
@Override
public GuardedInvocation getGuardedInvocation(final LinkRequest origRequest, final LinkerServices linkerServices)
throws Exception {
+ checkLinkRequest(origRequest);
+ // let the next linker deal with actual linking
+ return null;
+ }
+
+ static void checkReflectionAccess(Class<?> clazz) {
+ final SecurityManager sm = System.getSecurityManager();
+ if (sm != null && isReflectionClass(clazz)) {
+ checkReflectionPermission(sm);
+ }
+ }
+
+ private static void checkLinkRequest(final LinkRequest origRequest) {
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
final LinkRequest requestWithoutContext = origRequest.withoutRuntimeContext(); // Nashorn has no runtime context
@@ -61,23 +74,19 @@
// allow 'static' access on Class objects representing public classes of non-restricted packages
if ((self instanceof Class) && Modifier.isPublic(((Class<?>)self).getModifiers())) {
final CallSiteDescriptor desc = requestWithoutContext.getCallSiteDescriptor();
- final String operator = CallSiteDescriptorFactory.tokenizeOperators(desc).get(0);
- // check for 'get' on 'static' property
- switch (operator) {
- case "getProp":
- case "getMethod": {
- if ("static".equals(desc.getNameToken(CallSiteDescriptor.NAME_OPERAND))) {
- Context.checkPackageAccess(((Class)self).getName());
- // let bean linker do the actual linking part
- return null;
- }
+ if(CallSiteDescriptorFactory.tokenizeOperators(desc).contains("getProp")) {
+ if ("static".equals(desc.getNameToken(CallSiteDescriptor.NAME_OPERAND))) {
+ Context.checkPackageAccess(((Class)self).getName());
+ // If "getProp:static" passes package access, allow access.
+ return;
}
- break;
- } // fall through for all other stuff
+ }
}
- sm.checkPermission(new RuntimePermission("nashorn.JavaReflection"));
+ checkReflectionPermission(sm);
}
- // let the next linker deal with actual linking
- return null;
+ }
+
+ private static void checkReflectionPermission(final SecurityManager sm) {
+ sm.checkPermission(new RuntimePermission("nashorn.JavaReflection"));
}
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8020508.js Mon Jul 15 16:31:49 2013 +0200
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2010, 2013, 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.
+ */
+
+/**
+ * JDK-8020508: Enforce reflection check on
+ * Object.bindProperties(target, source) for beans
+ *
+ * @test
+ * @run
+ */
+
+var x = {}
+try {
+ Object.bindProperties(x, java.util.Vector.class)
+} catch(e) {
+ print(e)
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/nashorn/test/script/basic/JDK-8020508.js.EXPECTED Mon Jul 15 16:31:49 2013 +0200
@@ -0,0 +1,1 @@
+java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "nashorn.JavaReflection")