ReflectionCheckLinker.java revision 1551:f3b883bec2d0
1/* 2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26package jdk.nashorn.internal.runtime.linker; 27 28import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; 29 30import java.lang.reflect.Modifier; 31import java.lang.reflect.Proxy; 32import jdk.dynalink.CallSiteDescriptor; 33import jdk.dynalink.StandardOperation; 34import jdk.dynalink.linker.GuardedInvocation; 35import jdk.dynalink.linker.LinkRequest; 36import jdk.dynalink.linker.LinkerServices; 37import jdk.dynalink.linker.TypeBasedGuardingDynamicLinker; 38import jdk.nashorn.api.scripting.ClassFilter; 39import jdk.nashorn.internal.objects.Global; 40import jdk.nashorn.internal.runtime.Context; 41 42/** 43 * Check java reflection permission for java reflective and java.lang.invoke access from scripts 44 */ 45final class ReflectionCheckLinker implements TypeBasedGuardingDynamicLinker{ 46 private static final Class<?> STATEMENT_CLASS = getBeanClass("Statement"); 47 private static final Class<?> XMLENCODER_CLASS = getBeanClass("XMLEncoder"); 48 private static final Class<?> XMLDECODER_CLASS = getBeanClass("XMLDecoder"); 49 50 private static Class<?> getBeanClass(final String name) { 51 try { 52 return Class.forName("java.beans." + name); 53 } catch (final ClassNotFoundException cnfe) { 54 // Possible to miss this class in other profiles. 55 return null; 56 } 57 } 58 59 @Override 60 public boolean canLinkType(final Class<?> type) { 61 return isReflectionClass(type); 62 } 63 64 private static boolean isReflectionClass(final Class<?> type) { 65 // Class or ClassLoader subclasses 66 if (type == Class.class || ClassLoader.class.isAssignableFrom(type)) { 67 return true; 68 } 69 70 // check for bean reflection 71 if ((STATEMENT_CLASS != null && STATEMENT_CLASS.isAssignableFrom(type)) || 72 (XMLENCODER_CLASS != null && XMLENCODER_CLASS.isAssignableFrom(type)) || 73 (XMLDECODER_CLASS != null && XMLDECODER_CLASS.isAssignableFrom(type))) { 74 return true; 75 } 76 77 // package name check 78 final String name = type.getName(); 79 return name.startsWith("java.lang.reflect.") || name.startsWith("java.lang.invoke."); 80 } 81 82 @Override 83 public GuardedInvocation getGuardedInvocation(final LinkRequest origRequest, final LinkerServices linkerServices) 84 throws Exception { 85 checkLinkRequest(origRequest); 86 // let the next linker deal with actual linking 87 return null; 88 } 89 90 private static boolean isReflectiveCheckNeeded(final Class<?> type, final boolean isStatic) { 91 // special handling for Proxy subclasses 92 if (Proxy.class.isAssignableFrom(type)) { 93 if (Proxy.isProxyClass(type)) { 94 // real Proxy class - filter only static access 95 return isStatic; 96 } 97 98 // fake Proxy subclass - filter it always! 99 return true; 100 } 101 102 // check for any other reflective Class 103 return isReflectionClass(type); 104 } 105 106 static void checkReflectionAccess(final Class<?> clazz, final boolean isStatic) { 107 final Global global = Context.getGlobal(); 108 final ClassFilter cf = global.getClassFilter(); 109 if (cf != null && isReflectiveCheckNeeded(clazz, isStatic)) { 110 throw typeError("no.reflection.with.classfilter"); 111 } 112 113 final SecurityManager sm = System.getSecurityManager(); 114 if (sm != null && isReflectiveCheckNeeded(clazz, isStatic)) { 115 checkReflectionPermission(sm); 116 } 117 } 118 119 private static void checkLinkRequest(final LinkRequest request) { 120 final Global global = Context.getGlobal(); 121 final ClassFilter cf = global.getClassFilter(); 122 if (cf != null) { 123 throw typeError("no.reflection.with.classfilter"); 124 } 125 126 final SecurityManager sm = System.getSecurityManager(); 127 if (sm != null) { 128 final Object self = request.getReceiver(); 129 // allow 'static' access on Class objects representing public classes of non-restricted packages 130 if ((self instanceof Class) && Modifier.isPublic(((Class<?>)self).getModifiers())) { 131 final CallSiteDescriptor desc = request.getCallSiteDescriptor(); 132 if ("static".equals(NashornCallSiteDescriptor.getOperand(desc)) && NashornCallSiteDescriptor.contains(desc, StandardOperation.GET_PROPERTY)) { 133 if (Context.isAccessibleClass((Class<?>)self) && !isReflectionClass((Class<?>)self)) { 134 // If "GET_PROPERTY:static" passes access checks, allow access. 135 return; 136 } 137 } 138 } 139 checkReflectionPermission(sm); 140 } 141 } 142 143 private static void checkReflectionPermission(final SecurityManager sm) { 144 sm.checkPermission(new RuntimePermission(Context.NASHORN_JAVA_REFLECTION)); 145 } 146} 147