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 java.lang.reflect.Modifier;
  29 import java.lang.reflect.Proxy;
  30 import jdk.internal.dynalink.CallSiteDescriptor;
  31 import jdk.internal.dynalink.linker.GuardedInvocation;
  32 import jdk.internal.dynalink.linker.LinkRequest;
  33 import jdk.internal.dynalink.linker.LinkerServices;
  34 import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker;
  35 import jdk.internal.dynalink.support.CallSiteDescriptorFactory;
  36 import jdk.nashorn.internal.runtime.Context;
  37 
  38 /**
  39  * Check java reflection permission for java reflective and java.lang.invoke access from scripts
  40  */
  41 final class ReflectionCheckLinker implements TypeBasedGuardingDynamicLinker{
  42     @Override
  43     public boolean canLinkType(final Class<?> type) {
  44         return isReflectionClass(type);
  45     }
  46 
  47     private static boolean isReflectionClass(final Class<?> type) {
  48         if (type == Class.class || ClassLoader.class.isAssignableFrom(type)) {
  49             return true;
  50         }
  51 
  52         final String name = type.getName();
  53         return name.startsWith("java.lang.reflect.") || name.startsWith("java.lang.invoke.");
  54     }
  55 
  56     @Override
  57     public GuardedInvocation getGuardedInvocation(final LinkRequest origRequest, final LinkerServices linkerServices)
  58             throws Exception {
  59         checkLinkRequest(origRequest);
  60         // let the next linker deal with actual linking
  61         return null;
  62     }
  63 
  64     private static boolean isReflectiveCheckNeeded(final Class<?> type, final boolean isStatic) {
  65          // special handling for Proxy subclasses
  66          if (Proxy.class.isAssignableFrom(type)) {
  67             if (Proxy.isProxyClass(type)) {
  68                 // real Proxy class - filter only static access
  69                 return isStatic;
  70             }
  71 
  72             // fake Proxy subclass - filter it always!
  73             return true;
  74         }
  75 
  76         // check for any other reflective Class
  77         return isReflectionClass(type);
  78     }
  79 
  80     static void checkReflectionAccess(final Class<?> clazz, final boolean isStatic) {
  81         final SecurityManager sm = System.getSecurityManager();
  82         if (sm != null && isReflectiveCheckNeeded(clazz, isStatic)) {
  83             checkReflectionPermission(sm);
  84         }
  85     }
  86 
  87     private static void checkLinkRequest(final LinkRequest origRequest) {
  88         final SecurityManager sm = System.getSecurityManager();
  89         if (sm != null) {
  90             final LinkRequest requestWithoutContext = origRequest.withoutRuntimeContext(); // Nashorn has no runtime context
  91             final Object self = requestWithoutContext.getReceiver();
  92             // allow 'static' access on Class objects representing public classes of non-restricted packages
  93             if ((self instanceof Class) && Modifier.isPublic(((Class<?>)self).getModifiers())) {
  94                 final CallSiteDescriptor desc = requestWithoutContext.getCallSiteDescriptor();
  95                 if(CallSiteDescriptorFactory.tokenizeOperators(desc).contains("getProp")) {
  96                     if (desc.getNameTokenCount() > CallSiteDescriptor.NAME_OPERAND &&
  97                         "static".equals(desc.getNameToken(CallSiteDescriptor.NAME_OPERAND))) {
  98                         if (Context.isAccessibleClass((Class<?>)self) && !isReflectionClass((Class<?>)self)) {
  99 
 100                             // If "getProp:static" passes access checks, allow access.
 101                             return;
 102                         }
 103                     }
 104                 }
 105             }
 106             checkReflectionPermission(sm);
 107         }
 108     }
 109 
 110     private static void checkReflectionPermission(final SecurityManager sm) {
 111         sm.checkPermission(new RuntimePermission(Context.NASHORN_JAVA_REFLECTION));
 112     }
 113 }