# HG changeset patch # User attila # Date 1375886324 -7200 # Node ID b972b61a69213a488fe39a4d41aafadd2a1e12f7 # Parent 73d242d205f9af6a300d7014d5cc688fdc92f604 8022509: Various Dynalink security enhancements Reviewed-by: jlaskey, hannesw diff -r 73d242d205f9 -r b972b61a6921 nashorn/src/jdk/internal/dynalink/ChainedCallSite.java --- a/nashorn/src/jdk/internal/dynalink/ChainedCallSite.java Thu Aug 01 12:23:38 2013 +0200 +++ b/nashorn/src/jdk/internal/dynalink/ChainedCallSite.java Wed Aug 07 16:38:44 2013 +0200 @@ -85,12 +85,12 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; import java.util.Iterator; import java.util.LinkedList; import java.util.concurrent.atomic.AtomicReference; import jdk.internal.dynalink.linker.GuardedInvocation; import jdk.internal.dynalink.support.AbstractRelinkableCallSite; +import jdk.internal.dynalink.support.Lookup; /** * A relinkable call site that maintains a chain of linked method handles. In the default implementation, up to 8 method @@ -103,6 +103,9 @@ * handle is always at the start of the chain. */ public class ChainedCallSite extends AbstractRelinkableCallSite { + private static final MethodHandle PRUNE = Lookup.findOwnSpecial(MethodHandles.lookup(), "prune", MethodHandle.class, + MethodHandle.class); + private final AtomicReference> invocations = new AtomicReference<>(); /** @@ -194,18 +197,4 @@ private MethodHandle prune(MethodHandle relink) { return relinkInternal(null, relink, false); } - - private static final MethodHandle PRUNE; - static { - try { - PRUNE = MethodHandles.lookup().findSpecial(ChainedCallSite.class, "prune", MethodType.methodType( - MethodHandle.class, MethodHandle.class), ChainedCallSite.class); - // NOTE: using two catch blocks so we don't introduce a reference to 1.7 ReflectiveOperationException, allowing - // Dynalink to be used on 1.6 JVMs with Remi's backport library. - } catch(IllegalAccessException e) { - throw new AssertionError(e.getMessage(), e); // Can not happen - } catch(NoSuchMethodException e) { - throw new AssertionError(e.getMessage(), e); // Can not happen - } - } } diff -r 73d242d205f9 -r b972b61a6921 nashorn/src/jdk/internal/dynalink/DynamicLinkerFactory.java --- a/nashorn/src/jdk/internal/dynalink/DynamicLinkerFactory.java Thu Aug 01 12:23:38 2013 +0200 +++ b/nashorn/src/jdk/internal/dynalink/DynamicLinkerFactory.java Wed Aug 07 16:38:44 2013 +0200 @@ -84,6 +84,8 @@ package jdk.internal.dynalink; import java.lang.invoke.MutableCallSite; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -117,7 +119,9 @@ */ public static final int DEFAULT_UNSTABLE_RELINK_THRESHOLD = 8; - private ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); + private boolean classLoaderExplicitlySet = false; + private ClassLoader classLoader; + private List prioritizedLinkers; private List fallbackLinkers; private int runtimeContextArgCount = 0; @@ -126,12 +130,13 @@ /** * Sets the class loader for automatic discovery of available linkers. If not set explicitly, then the thread - * context class loader at the time of the constructor invocation will be used. + * context class loader at the time of {@link #createLinker()} invocation will be used. * * @param classLoader the class loader used for the autodiscovery of available linkers. */ public void setClassLoader(ClassLoader classLoader) { this.classLoader = classLoader; + classLoaderExplicitlySet = true; } /** @@ -260,7 +265,8 @@ addClasses(knownLinkerClasses, prioritizedLinkers); addClasses(knownLinkerClasses, fallbackLinkers); - final List discovered = AutoDiscovery.loadLinkers(classLoader); + final ClassLoader effectiveClassLoader = classLoaderExplicitlySet ? classLoader : getThreadContextClassLoader(); + final List discovered = AutoDiscovery.loadLinkers(effectiveClassLoader); // Now, concatenate ... final List linkers = new ArrayList<>(prioritizedLinkers.size() + discovered.size() @@ -303,6 +309,15 @@ runtimeContextArgCount, syncOnRelink, unstableRelinkThreshold); } + private static ClassLoader getThreadContextClassLoader() { + return AccessController.doPrivileged(new PrivilegedAction() { + @Override + public ClassLoader run() { + return Thread.currentThread().getContextClassLoader(); + } + }); + } + private static void addClasses(Set> knownLinkerClasses, List linkers) { for(GuardingDynamicLinker linker: linkers) { diff -r 73d242d205f9 -r b972b61a6921 nashorn/src/jdk/internal/dynalink/beans/ClassString.java --- a/nashorn/src/jdk/internal/dynalink/beans/ClassString.java Thu Aug 01 12:23:38 2013 +0200 +++ b/nashorn/src/jdk/internal/dynalink/beans/ClassString.java Wed Aug 07 16:38:44 2013 +0200 @@ -112,10 +112,6 @@ this(type.parameterArray()); } - Class[] getClasses() { - return classes; - } - @Override public boolean equals(Object other) { if(!(other instanceof ClassString)) { diff -r 73d242d205f9 -r b972b61a6921 nashorn/src/jdk/internal/dynalink/beans/StaticClassLinker.java --- a/nashorn/src/jdk/internal/dynalink/beans/StaticClassLinker.java Thu Aug 01 12:23:38 2013 +0200 +++ b/nashorn/src/jdk/internal/dynalink/beans/StaticClassLinker.java Wed Aug 07 16:38:44 2013 +0200 @@ -189,15 +189,17 @@ return type == StaticClass.class; } - /*private*/ static final MethodHandle GET_CLASS = new Lookup(MethodHandles.lookup()).findVirtual(StaticClass.class, - "getRepresentedClass", MethodType.methodType(Class.class)); - - /*private*/ static final MethodHandle IS_CLASS = new Lookup(MethodHandles.lookup()).findStatic(StaticClassLinker.class, - "isClass", MethodType.methodType(Boolean.TYPE, Class.class, Object.class)); - + /*private*/ static final MethodHandle GET_CLASS; + /*private*/ static final MethodHandle IS_CLASS; /*private*/ static final MethodHandle ARRAY_CTOR = Lookup.PUBLIC.findStatic(Array.class, "newInstance", MethodType.methodType(Object.class, Class.class, int.class)); + static { + final Lookup lookup = new Lookup(MethodHandles.lookup()); + GET_CLASS = lookup.findVirtual(StaticClass.class, "getRepresentedClass", MethodType.methodType(Class.class)); + IS_CLASS = lookup.findOwnStatic("isClass", Boolean.TYPE, Class.class, Object.class); + } + @SuppressWarnings("unused") private static boolean isClass(Class clazz, Object obj) { return obj instanceof StaticClass && ((StaticClass)obj).getRepresentedClass() == clazz; diff -r 73d242d205f9 -r b972b61a6921 nashorn/src/jdk/internal/dynalink/support/Backport.java --- a/nashorn/src/jdk/internal/dynalink/support/Backport.java Thu Aug 01 12:23:38 2013 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,99 +0,0 @@ -/* - * 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. Oracle designates this - * particular file as subject to the "Classpath" exception as provided - * by Oracle in the LICENSE file that accompanied this code. - * - * 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. - */ - -/* - * This file is available under and governed by the GNU General Public - * License version 2 only, as published by the Free Software Foundation. - * However, the following notice accompanied the original version of this - * file, and Oracle licenses the original version of this file under the BSD - * license: - */ -/* - Copyright 2009-2013 Attila Szegedi - - Licensed under both the Apache License, Version 2.0 (the "Apache License") - and the BSD License (the "BSD License"), with licensee being free to - choose either of the two at their discretion. - - You may not use this file except in compliance with either the Apache - License or the BSD License. - - If you choose to use this file in compliance with the Apache License, the - following notice applies to you: - - You may obtain a copy of the Apache License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied. See the License for the specific language governing - permissions and limitations under the License. - - If you choose to use this file in compliance with the BSD License, the - following notice applies to you: - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are - met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the copyright holder nor the names of - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS - IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER - BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR - BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ - -package jdk.internal.dynalink.support; - -import java.lang.invoke.MethodHandles; - -/** - * @author Attila Szegedi - */ -public class Backport { - /** - * True if Remi's JSR-292 backport agent is active; false if we're using native OpenJDK JSR-292 support. - */ - public static final boolean inUse = MethodHandles.class.getName().startsWith("jsr292"); - - private Backport() { - } -} diff -r 73d242d205f9 -r b972b61a6921 nashorn/src/jdk/internal/dynalink/support/ClassMap.java --- a/nashorn/src/jdk/internal/dynalink/support/ClassMap.java Thu Aug 01 12:23:38 2013 +0200 +++ b/nashorn/src/jdk/internal/dynalink/support/ClassMap.java Wed Aug 07 16:38:44 2013 +0200 @@ -85,6 +85,8 @@ import java.lang.ref.Reference; import java.lang.ref.SoftReference; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.Map; import java.util.WeakHashMap; import java.util.concurrent.ConcurrentHashMap; @@ -122,21 +124,12 @@ protected abstract T computeValue(Class clazz); /** - * Returns the class loader that governs the strong referenceability of this class map. - * - * @return the class loader that governs the strong referenceability of this class map. - */ - public ClassLoader getClassLoader() { - return classLoader; - } - - /** * Returns the value associated with the class * * @param clazz the class * @return the value associated with the class */ - public T get(Class clazz) { + public T get(final Class clazz) { // Check in fastest first - objects we're allowed to strongly reference final T v = map.get(clazz); if(v != null) { @@ -156,8 +149,16 @@ // Not found in either place; create a new value final T newV = computeValue(clazz); assert newV != null; + + final ClassLoader clazzLoader = AccessController.doPrivileged(new PrivilegedAction() { + @Override + public ClassLoader run() { + return clazz.getClassLoader(); + } + }); + // If allowed to strongly reference, put it in the fast map - if(Guards.canReferenceDirectly(classLoader, clazz.getClassLoader())) { + if(Guards.canReferenceDirectly(classLoader, clazzLoader)) { final T oldV = map.putIfAbsent(clazz, newV); return oldV != null ? oldV : newV; } diff -r 73d242d205f9 -r b972b61a6921 nashorn/src/jdk/internal/dynalink/support/Guards.java --- a/nashorn/src/jdk/internal/dynalink/support/Guards.java Thu Aug 01 12:23:38 2013 +0200 +++ b/nashorn/src/jdk/internal/dynalink/support/Guards.java Wed Aug 07 16:38:44 2013 +0200 @@ -258,23 +258,24 @@ type.changeReturnType(Boolean.TYPE), new int[] { pos }); } - private static final MethodHandle IS_OF_CLASS = new Lookup(MethodHandles.lookup()).findStatic(Guards.class, - "isOfClass", MethodType.methodType(Boolean.TYPE, Class.class, Object.class)); - private static final MethodHandle IS_INSTANCE = Lookup.PUBLIC.findVirtual(Class.class, "isInstance", MethodType.methodType(Boolean.TYPE, Object.class)); - private static final MethodHandle IS_ARRAY = new Lookup(MethodHandles.lookup()).findStatic(Guards.class, "isArray", - MethodType.methodType(Boolean.TYPE, Object.class)); - - private static final MethodHandle IS_IDENTICAL = new Lookup(MethodHandles.lookup()).findStatic(Guards.class, - "isIdentical", MethodType.methodType(Boolean.TYPE, Object.class, Object.class)); + private static final MethodHandle IS_OF_CLASS; + private static final MethodHandle IS_ARRAY; + private static final MethodHandle IS_IDENTICAL; + private static final MethodHandle IS_NULL; + private static final MethodHandle IS_NOT_NULL; - private static final MethodHandle IS_NULL = new Lookup(MethodHandles.lookup()).findStatic(Guards.class, - "isNull", MethodType.methodType(Boolean.TYPE, Object.class)); + static { + final Lookup lookup = new Lookup(MethodHandles.lookup()); - private static final MethodHandle IS_NOT_NULL = new Lookup(MethodHandles.lookup()).findStatic(Guards.class, - "isNotNull", MethodType.methodType(Boolean.TYPE, Object.class)); + IS_OF_CLASS = lookup.findOwnStatic("isOfClass", Boolean.TYPE, Class.class, Object.class); + IS_ARRAY = lookup.findOwnStatic("isArray", Boolean.TYPE, Object.class); + IS_IDENTICAL = lookup.findOwnStatic("isIdentical", Boolean.TYPE, Object.class, Object.class); + IS_NULL = lookup.findOwnStatic("isNull", Boolean.TYPE, Object.class); + IS_NOT_NULL = lookup.findOwnStatic("isNotNull", Boolean.TYPE, Object.class); + } /** * Creates a guard method that tests its only argument for being of an exact particular class. diff -r 73d242d205f9 -r b972b61a6921 nashorn/src/jdk/internal/dynalink/support/Lookup.java --- a/nashorn/src/jdk/internal/dynalink/support/Lookup.java Thu Aug 01 12:23:38 2013 +0200 +++ b/nashorn/src/jdk/internal/dynalink/support/Lookup.java Wed Aug 07 16:38:44 2013 +0200 @@ -89,7 +89,6 @@ import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; -import java.lang.reflect.Modifier; /** * A wrapper around MethodHandles.Lookup that masks checked exceptions in those cases when you're looking up methods @@ -235,9 +234,8 @@ } /** - * Performs a findSpecial on the underlying lookup, except for the backport where it rather uses unreflect. Converts - * any encountered {@link IllegalAccessException} into an {@link IllegalAccessError} and a - * {@link NoSuchMethodException} into a {@link NoSuchMethodError}. + * Performs a findSpecial on the underlying lookup. Converts any encountered {@link IllegalAccessException} into an + * {@link IllegalAccessError} and a {@link NoSuchMethodException} into a {@link NoSuchMethodError}. * * @param declaringClass class declaring the method * @param name the name of the method @@ -248,13 +246,6 @@ */ public MethodHandle findSpecial(Class declaringClass, String name, MethodType type) { try { - if(Backport.inUse) { - final Method m = declaringClass.getDeclaredMethod(name, type.parameterArray()); - if(!Modifier.isPublic(declaringClass.getModifiers()) || !Modifier.isPublic(m.getModifiers())) { - m.setAccessible(true); - } - return unreflect(m); - } return lookup.findSpecial(declaringClass, name, type, declaringClass); } catch(IllegalAccessException e) { final IllegalAccessError ee = new IllegalAccessError("Failed to access special method " + methodDescription( diff -r 73d242d205f9 -r b972b61a6921 nashorn/src/jdk/internal/dynalink/support/TypeConverterFactory.java --- a/nashorn/src/jdk/internal/dynalink/support/TypeConverterFactory.java Thu Aug 01 12:23:38 2013 +0200 +++ b/nashorn/src/jdk/internal/dynalink/support/TypeConverterFactory.java Wed Aug 07 16:38:44 2013 +0200 @@ -87,6 +87,8 @@ import java.lang.invoke.MethodHandles; import java.lang.invoke.MethodType; import java.lang.invoke.WrongMethodTypeException; +import java.security.AccessController; +import java.security.PrivilegedAction; import java.util.LinkedList; import java.util.List; import jdk.internal.dynalink.linker.ConversionComparator; @@ -110,7 +112,7 @@ private final ClassValue> converterMap = new ClassValue>() { @Override protected ClassMap computeValue(final Class sourceType) { - return new ClassMap(sourceType.getClassLoader()) { + return new ClassMap(getClassLoader(sourceType)) { @Override protected MethodHandle computeValue(Class targetType) { try { @@ -128,7 +130,7 @@ private final ClassValue> converterIdentityMap = new ClassValue>() { @Override protected ClassMap computeValue(final Class sourceType) { - return new ClassMap(sourceType.getClassLoader()) { + return new ClassMap(getClassLoader(sourceType)) { @Override protected MethodHandle computeValue(Class targetType) { if(!canAutoConvert(sourceType, targetType)) { @@ -143,6 +145,15 @@ } }; + private static final ClassLoader getClassLoader(final Class clazz) { + return AccessController.doPrivileged(new PrivilegedAction() { + @Override + public ClassLoader run() { + return clazz.getClassLoader(); + } + }); + } + /** * Creates a new type converter factory from the available {@link GuardingTypeConverterFactory} instances. * diff -r 73d242d205f9 -r b972b61a6921 nashorn/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java --- a/nashorn/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java Thu Aug 01 12:23:38 2013 +0200 +++ b/nashorn/src/jdk/nashorn/internal/runtime/linker/Bootstrap.java Wed Aug 07 16:38:44 2013 +0200 @@ -68,6 +68,10 @@ if (relinkThreshold > -1) { factory.setUnstableRelinkThreshold(relinkThreshold); } + + // Linkers for any additional language runtimes deployed alongside Nashorn will be picked up by the factory. + factory.setClassLoader(Bootstrap.class.getClassLoader()); + dynamicLinker = factory.createLinker(); }