1 /*
   2  * Copyright (c) 2005, 2006, 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 com.sun.script.javascript;
  27 
  28 import java.lang.reflect.*;
  29 import static sun.security.util.SecurityConstants.*;
  30 import sun.org.mozilla.javascript.internal.*;
  31 
  32 /**
  33  * This wrap factory is used for security reasons. JSR 223 script
  34  * engine interface and JavaScript engine classes are run as bootstrap
  35  * classes. For example, java.lang.Class.forName method (when called without
  36  * class loader) uses caller's class loader. This may be exploited by script
  37  * authors to access classes otherwise not accessible. For example,
  38  * classes in sun.* namespace are normally not accessible to untrusted
  39  * code and hence should not be accessible to JavaScript run from
  40  * untrusted code.
  41  *
  42  * @author A. Sundararajan
  43  * @since 1.6
  44  */
  45 final class RhinoWrapFactory extends WrapFactory {
  46     private RhinoWrapFactory() {}
  47     private static RhinoWrapFactory theInstance;
  48 
  49     static synchronized WrapFactory getInstance() {
  50         if (theInstance == null) {
  51             theInstance = new RhinoWrapFactory();
  52         }
  53         return theInstance;
  54     }
  55 
  56     // We use instance of this class to wrap security sensitive
  57     // Java object. Please refer below.
  58     private static class RhinoJavaObject extends NativeJavaObject {
  59         RhinoJavaObject(Scriptable scope, Object obj, Class type) {
  60             // we pass 'null' to object. NativeJavaObject uses
  61             // passed 'type' to reflect fields and methods when
  62             // object is null.
  63             super(scope, null, type);
  64 
  65             // Now, we set actual object. 'javaObject' is protected
  66             // field of NativeJavaObject.
  67             javaObject = obj;
  68         }
  69     }
  70 
  71     public Scriptable wrapAsJavaObject(Context cx, Scriptable scope,
  72             Object javaObject, Class staticType) {
  73         SecurityManager sm = System.getSecurityManager();
  74         ClassShutter classShutter = RhinoClassShutter.getInstance();
  75         if (javaObject instanceof ClassLoader) {
  76             // Check with Security Manager whether we can expose a
  77             // ClassLoader...
  78             if (sm != null) {
  79                 sm.checkPermission(GET_CLASSLOADER_PERMISSION);
  80             }
  81             // if we fall through here, check permission succeeded.
  82             return super.wrapAsJavaObject(cx, scope, javaObject, staticType);
  83         } else {
  84             String name = null;
  85             if (javaObject instanceof Class) {
  86                 name = ((Class)javaObject).getName();
  87             } else if (javaObject instanceof Member) {
  88                 Member member = (Member) javaObject;
  89                 // Check member access. Don't allow reflective access to
  90                 // non-public members. Note that we can't call checkMemberAccess
  91                 // because that expects exact stack depth!
  92                 if (sm != null && !Modifier.isPublic(member.getModifiers())) {
  93                     return null;
  94                 }
  95                 name = member.getDeclaringClass().getName();
  96             }
  97             // Now, make sure that no ClassShutter prevented Class or Member
  98             // of it is accessed reflectively. Note that ClassShutter may
  99             // prevent access to a class, even though SecurityManager permit.
 100             if (name != null) {
 101                 if (!classShutter.visibleToScripts(name)) {
 102                     return null;
 103                 } else {
 104                     return super.wrapAsJavaObject(cx, scope, javaObject, staticType);
 105                 }
 106             }
 107         }
 108 
 109         // we have got some non-reflective object.
 110         Class dynamicType = javaObject.getClass();
 111         String name = dynamicType.getName();
 112         if (!classShutter.visibleToScripts(name)) {
 113             // Object of some sensitive class (such as sun.net.www.*
 114             // objects returned from public method of java.net.URL class.
 115             // We expose this object as though it is an object of some
 116             // super class that is safe for access.
 117 
 118             Class type = null;
 119 
 120             // Whenever a Java Object is wrapped, we are passed with a
 121             // staticType which is the type found from environment. For
 122             // example, method return type known from signature. The dynamic
 123             // type would be the actual Class of the actual returned object.
 124             // If the staticType is an interface, we just use that type.
 125             if (staticType != null && staticType.isInterface()) {
 126                 type = staticType;
 127             } else {
 128                 // dynamicType is always a class type and never an interface.
 129                 // find an accessible super class of the dynamic type.
 130                 while (dynamicType != null) {
 131                     dynamicType = dynamicType.getSuperclass();
 132                     name = dynamicType.getName();
 133                     if (classShutter.visibleToScripts(name)) {
 134                          type = dynamicType; break;
 135                     }
 136                 }
 137                 // atleast java.lang.Object has to be accessible. So, when
 138                 // we reach here, type variable should not be null.
 139                 assert type != null:
 140                        "even java.lang.Object is not accessible?";
 141             }
 142             // create custom wrapper with the 'safe' type.
 143             return new RhinoJavaObject(scope, javaObject, type);
 144         } else {
 145             return super.wrapAsJavaObject(cx, scope, javaObject, staticType);
 146         }
 147     }
 148 }