1 /* 2 * Copyright (c) 1997, 2015, 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 java.security; 27 28 import java.net.URL; 29 import java.util.ArrayList; 30 import java.util.Map; 31 import java.util.Objects; 32 import java.util.concurrent.ConcurrentHashMap; 33 import java.util.function.Function; 34 35 import sun.security.util.Debug; 36 37 /** 38 * This class extends ClassLoader with additional support for defining 39 * classes with an associated code source and permissions which are 40 * retrieved by the system policy by default. 41 * 42 * @author Li Gong 43 * @author Roland Schemers 44 */ 45 public class SecureClassLoader extends ClassLoader { 46 /* 47 * If initialization succeed this is set to true and security checks will 48 * succeed. Otherwise the object is not initialized and the object is 49 * useless. 50 */ 51 private final boolean initialized; 52 53 /* 54 * Map that maps the CodeSource to a ProtectionDomain. The key is a 55 * CodeSourceKey class that uses a String instead of a URL to avoid 56 * potential expensive name service lookups. This does mean that URLs that 57 * are equivalent after nameservice lookup will be placed in separate 58 * ProtectionDomains; however during policy enforcement these URLs will be 59 * canonicalized and resolved resulting in a consistent set of granted 60 * permissions. 61 */ 62 private final Map<CodeSourceKey, ProtectionDomain> pdcache 63 = new ConcurrentHashMap<>(11); 64 65 static { 66 ClassLoader.registerAsParallelCapable(); 67 } 68 69 /** 70 * Creates a new SecureClassLoader using the specified parent 71 * class loader for delegation. 72 * 73 * <p>If there is a security manager, this method first 74 * calls the security manager's {@code checkCreateClassLoader} 75 * method to ensure creation of a class loader is allowed. 76 * 77 * @param parent the parent ClassLoader 78 * @exception SecurityException if a security manager exists and its 79 * {@code checkCreateClassLoader} method doesn't allow 80 * creation of a class loader. 81 * @see SecurityManager#checkCreateClassLoader 82 */ 83 protected SecureClassLoader(ClassLoader parent) { 84 super(parent); 85 // this is to make the stack depth consistent with 1.1 86 SecurityManager security = System.getSecurityManager(); 87 if (security != null) { 88 security.checkCreateClassLoader(); 89 } 90 initialized = true; 91 } 92 93 /** 94 * Creates a new SecureClassLoader using the default parent class 95 * loader for delegation. 96 * 97 * <p>If there is a security manager, this method first 98 * calls the security manager's {@code checkCreateClassLoader} 99 * method to ensure creation of a class loader is allowed. 100 * 101 * @exception SecurityException if a security manager exists and its 102 * {@code checkCreateClassLoader} method doesn't allow 103 * creation of a class loader. 104 * @see SecurityManager#checkCreateClassLoader 105 */ 106 protected SecureClassLoader() { 107 super(); 108 // this is to make the stack depth consistent with 1.1 109 SecurityManager security = System.getSecurityManager(); 110 if (security != null) { 111 security.checkCreateClassLoader(); 112 } 113 initialized = true; 114 } 115 116 /** 117 * Converts an array of bytes into an instance of class Class, 118 * with an optional CodeSource. Before the 119 * class can be used it must be resolved. 120 * <p> 121 * If a non-null CodeSource is supplied a ProtectionDomain is 122 * constructed and associated with the class being defined. 123 * 124 * @param name the expected name of the class, or {@code null} 125 * if not known, using '.' and not '/' as the separator 126 * and without a trailing ".class" suffix. 127 * @param b the bytes that make up the class data. The bytes in 128 * positions {@code off} through {@code off+len-1} 129 * should have the format of a valid class file as defined by 130 * <cite>The Java™ Virtual Machine Specification</cite>. 131 * @param off the start offset in {@code b} of the class data 132 * @param len the length of the class data 133 * @param cs the associated CodeSource, or {@code null} if none 134 * @return the {@code Class} object created from the data, 135 * and optional CodeSource. 136 * @exception ClassFormatError if the data did not contain a valid class 137 * @exception IndexOutOfBoundsException if either {@code off} or 138 * {@code len} is negative, or if 139 * {@code off+len} is greater than {@code b.length}. 140 * 141 * @exception SecurityException if an attempt is made to add this class 142 * to a package that contains classes that were signed by 143 * a different set of certificates than this class, or if 144 * the class name begins with "java.". 145 */ 146 protected final Class<?> defineClass(String name, 147 byte[] b, int off, int len, 148 CodeSource cs) 149 { 150 return defineClass(name, b, off, len, getProtectionDomain(cs)); 151 } 152 153 /** 154 * Converts a {@link java.nio.ByteBuffer ByteBuffer} 155 * into an instance of class {@code Class}, with an optional CodeSource. 156 * Before the class can be used it must be resolved. 157 * <p> 158 * If a non-null CodeSource is supplied a ProtectionDomain is 159 * constructed and associated with the class being defined. 160 * 161 * @param name the expected name of the class, or {@code null} 162 * if not known, using '.' and not '/' as the separator 163 * and without a trailing ".class" suffix. 164 * @param b the bytes that make up the class data. The bytes from positions 165 * {@code b.position()} through {@code b.position() + b.limit() -1} 166 * should have the format of a valid class file as defined by 167 * <cite>The Java™ Virtual Machine Specification</cite>. 168 * @param cs the associated CodeSource, or {@code null} if none 169 * @return the {@code Class} object created from the data, 170 * and optional CodeSource. 171 * @exception ClassFormatError if the data did not contain a valid class 172 * @exception SecurityException if an attempt is made to add this class 173 * to a package that contains classes that were signed by 174 * a different set of certificates than this class, or if 175 * the class name begins with "java.". 176 * 177 * @since 1.5 178 */ 179 protected final Class<?> defineClass(String name, java.nio.ByteBuffer b, 180 CodeSource cs) 181 { 182 return defineClass(name, b, getProtectionDomain(cs)); 183 } 184 185 /** 186 * Returns the permissions for the given CodeSource object. 187 * <p> 188 * This method is invoked by the defineClass method which takes 189 * a CodeSource as an argument when it is constructing the 190 * ProtectionDomain for the class being defined. 191 * 192 * @param codesource the codesource. 193 * 194 * @return the permissions granted to the codesource. 195 * 196 */ 197 protected PermissionCollection getPermissions(CodeSource codesource) 198 { 199 check(); 200 return new Permissions(); // ProtectionDomain defers the binding 201 } 202 203 /* 204 * holder class for the static field "debug" to delay its initialization 205 */ 206 private static class DebugHolder { 207 private static final Debug debug = Debug.getInstance("scl"); 208 } 209 210 /* 211 * Returned cached ProtectionDomain for the specified CodeSource. 212 */ 213 private ProtectionDomain getProtectionDomain(CodeSource cs) { 214 if (cs == null) { 215 return null; 216 } 217 218 // Use a CodeSourceKey object key. It should behave in the 219 // same manner as the CodeSource when compared for equality except 220 // that no nameservice lookup is done on the hostname (String comparison 221 // only), and the fragment is not considered. 222 CodeSourceKey key = new CodeSourceKey(cs); 223 return pdcache.computeIfAbsent(key, new Function<>() { 224 @Override 225 public ProtectionDomain apply(CodeSourceKey key /* not used */) { 226 PermissionCollection perms 227 = SecureClassLoader.this.getPermissions(cs); 228 ProtectionDomain pd = new ProtectionDomain( 229 cs, perms, SecureClassLoader.this, null); 230 if (DebugHolder.debug != null) { 231 DebugHolder.debug.println(" getPermissions " + pd); 232 DebugHolder.debug.println(""); 233 } 234 return pd; 235 } 236 }); 237 } 238 239 /* 240 * Check to make sure the class loader has been initialized. 241 */ 242 private void check() { 243 if (!initialized) { 244 throw new SecurityException("ClassLoader object not initialized"); 245 } 246 } 247 248 private static class CodeSourceKey { 249 private final CodeSource cs; 250 251 CodeSourceKey(CodeSource cs) { 252 this.cs = cs; 253 } 254 255 @Override 256 public int hashCode() { 257 String locationNoFrag = cs.getLocationNoFragString(); 258 return locationNoFrag != null ? locationNoFrag.hashCode() : 0; 259 } 260 261 @Override 262 public boolean equals(Object obj) { 263 if (obj == this) { 264 return true; 265 } 266 267 if (!(obj instanceof CodeSourceKey)) { 268 return false; 269 } 270 271 CodeSourceKey csk = (CodeSourceKey) obj; 272 273 if (!Objects.equals(cs.getLocationNoFragString(), 274 csk.cs.getLocationNoFragString())) { 275 return false; 276 } 277 278 return cs.matchCerts(csk.cs, true); 279 } 280 } 281 }