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 26 package jdk.nashorn.internal.runtime.linker; 27 28 import static jdk.nashorn.internal.runtime.ECMAErrors.typeError; 29 30 import java.lang.reflect.Modifier; 31 import java.lang.reflect.Proxy; 32 import jdk.dynalink.CallSiteDescriptor; 33 import jdk.dynalink.StandardNamespace; 34 import jdk.dynalink.StandardOperation; 35 import jdk.dynalink.linker.GuardedInvocation; 36 import jdk.dynalink.linker.LinkRequest; 37 import jdk.dynalink.linker.LinkerServices; 38 import jdk.dynalink.linker.TypeBasedGuardingDynamicLinker; 39 import jdk.nashorn.api.scripting.ClassFilter; 40 import jdk.nashorn.internal.objects.Global; 41 import jdk.nashorn.internal.runtime.Context; 42 43 /** 44 * Check java reflection permission for java reflective and java.lang.invoke access from scripts 45 */ 46 final class ReflectionCheckLinker implements TypeBasedGuardingDynamicLinker{ 47 private static final Class<?> STATEMENT_CLASS = getBeanClass("Statement"); 48 private static final Class<?> XMLENCODER_CLASS = getBeanClass("XMLEncoder"); 49 private static final Class<?> XMLDECODER_CLASS = getBeanClass("XMLDecoder"); 50 51 private static Class<?> getBeanClass(final String name) { 52 try { 53 return Class.forName("java.beans." + name); 54 } catch (final ClassNotFoundException cnfe) { 55 // Possible to miss this class in other profiles. 56 return null; 57 } 58 } 59 60 @Override 61 public boolean canLinkType(final Class<?> type) { 62 return isReflectionClass(type); 63 } 64 65 private static boolean isReflectionClass(final Class<?> type) { 66 // Class or ClassLoader subclasses 67 if (type == Class.class || ClassLoader.class.isAssignableFrom(type)) { 68 return true; 69 } 70 71 // check for bean reflection 72 if ((STATEMENT_CLASS != null && STATEMENT_CLASS.isAssignableFrom(type)) || 73 (XMLENCODER_CLASS != null && XMLENCODER_CLASS.isAssignableFrom(type)) || 74 (XMLDECODER_CLASS != null && XMLDECODER_CLASS.isAssignableFrom(type))) { 75 return true; 76 } 77 78 // package name check 79 final String name = type.getName(); 80 return name.startsWith("java.lang.reflect.") || name.startsWith("java.lang.invoke."); 81 } 82 83 @Override 84 public GuardedInvocation getGuardedInvocation(final LinkRequest origRequest, final LinkerServices linkerServices) 85 throws Exception { 86 checkLinkRequest(origRequest); 87 // let the next linker deal with actual linking 88 return null; 89 } 90 91 private static boolean isReflectiveCheckNeeded(final Class<?> type, final boolean isStatic) { 92 // special handling for Proxy subclasses 93 if (Proxy.class.isAssignableFrom(type)) { 94 if (Proxy.isProxyClass(type)) { 95 // real Proxy class - filter only static access 96 return isStatic; 97 } 98 99 // fake Proxy subclass - filter it always! 100 return true; 101 } 102 103 // check for any other reflective Class 104 return isReflectionClass(type); 105 } 106 107 static void checkReflectionAccess(final Class<?> clazz, final boolean isStatic) { 108 final Global global = Context.getGlobal(); 109 final ClassFilter cf = global.getClassFilter(); 110 if (cf != null && isReflectiveCheckNeeded(clazz, isStatic)) { 111 throw typeError("no.reflection.with.classfilter"); 112 } 113 114 final SecurityManager sm = System.getSecurityManager(); 115 if (sm != null && isReflectiveCheckNeeded(clazz, isStatic)) { 116 checkReflectionPermission(sm); 117 } 118 } 119 120 private static void checkLinkRequest(final LinkRequest request) { 121 final Global global = Context.getGlobal(); 122 final ClassFilter cf = global.getClassFilter(); 123 if (cf != null) { 124 throw typeError("no.reflection.with.classfilter"); 125 } 126 127 final SecurityManager sm = System.getSecurityManager(); 128 if (sm != null) { 129 final Object self = request.getReceiver(); 130 // allow 'static' access on Class objects representing public classes of non-restricted packages 131 if ((self instanceof Class) && Modifier.isPublic(((Class<?>)self).getModifiers())) { 132 final CallSiteDescriptor desc = request.getCallSiteDescriptor(); 133 if ("static".equals(NashornCallSiteDescriptor.getOperand(desc)) && NashornCallSiteDescriptor.contains(desc, StandardOperation.GET, StandardNamespace.PROPERTY)) { 134 if (Context.isAccessibleClass((Class<?>)self) && !isReflectionClass((Class<?>)self)) { 135 // If "GET:PROPERTY:static" passes access checks, allow access. 136 return; 137 } 138 } 139 } 140 checkReflectionPermission(sm); 141 } 142 } 143 144 private static void checkReflectionPermission(final SecurityManager sm) { 145 sm.checkPermission(new RuntimePermission(Context.NASHORN_JAVA_REFLECTION)); 146 } 147 }