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