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 }