1 /* 2 * Copyright (c) 1995, 2018, 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 sun.applet; 27 28 import java.io.File; 29 import java.io.FilePermission; 30 import java.io.IOException; 31 import java.io.FileDescriptor; 32 import java.net.URL; 33 import java.net.URLClassLoader; 34 import java.net.InetAddress; 35 import java.net.UnknownHostException; 36 import java.net.SocketPermission; 37 import java.util.Enumeration; 38 import java.util.Iterator; 39 import java.util.HashSet; 40 import java.util.StringTokenizer; 41 import java.security.*; 42 import java.lang.reflect.*; 43 import jdk.internal.misc.JavaNetURLClassLoaderAccess; 44 import jdk.internal.misc.JavaSecurityAccess; 45 import jdk.internal.misc.SharedSecrets; 46 import sun.awt.AWTSecurityManager; 47 import sun.awt.AppContext; 48 import sun.awt.AWTPermissions; 49 import sun.security.util.SecurityConstants; 50 51 import static java.lang.StackWalker.*; 52 import static java.lang.StackWalker.Option.*; 53 54 55 /** 56 * This class defines an applet security policy 57 * 58 */ 59 public 60 class AppletSecurity extends AWTSecurityManager { 61 private static final JavaNetURLClassLoaderAccess JNUCLA 62 = SharedSecrets.getJavaNetURLClassLoaderAccess(); 63 private static final JavaSecurityAccess JSA = SharedSecrets.getJavaSecurityAccess(); 64 65 /** 66 * Construct and initialize. 67 */ 68 public AppletSecurity() { 69 reset(); 70 } 71 72 // Cache to store known restricted packages 73 private HashSet<String> restrictedPackages = new HashSet<>(); 74 75 /** 76 * Reset from Properties 77 */ 78 public void reset() 79 { 80 // Clear cache 81 restrictedPackages.clear(); 82 83 AccessController.doPrivileged(new PrivilegedAction<Object>() { 84 public Object run() 85 { 86 // Enumerate system properties 87 Enumeration<?> e = System.getProperties().propertyNames(); 88 89 while (e.hasMoreElements()) 90 { 91 String name = (String) e.nextElement(); 92 93 if (name != null && name.startsWith("package.restrict.access.")) 94 { 95 String value = System.getProperty(name); 96 97 if (value != null && value.equalsIgnoreCase("true")) 98 { 99 String pkg = name.substring(24); 100 101 // Cache restricted packages 102 restrictedPackages.add(pkg); 103 } 104 } 105 } 106 return null; 107 } 108 }); 109 } 110 111 private static final StackWalker walker = 112 AccessController.doPrivileged( 113 (PrivilegedAction<StackWalker>) () -> 114 StackWalker.getInstance(RETAIN_CLASS_REFERENCE)); 115 /** 116 * Returns the class loader of the most recently executing method from 117 * a class defined using a non-system class loader. A non-system 118 * class loader is defined as being a class loader that is not equal to 119 * the system class loader (as returned 120 * by {@link ClassLoader#getSystemClassLoader}) or one of its ancestors. 121 * <p> 122 * This method will return 123 * <code>null</code> in the following three cases: 124 * <ol> 125 * <li>All methods on the execution stack are from classes 126 * defined using the system class loader or one of its ancestors. 127 * 128 * <li>All methods on the execution stack up to the first 129 * "privileged" caller 130 * (see {@link java.security.AccessController#doPrivileged}) 131 * are from classes 132 * defined using the system class loader or one of its ancestors. 133 * 134 * <li> A call to <code>checkPermission</code> with 135 * <code>java.security.AllPermission</code> does not 136 * result in a SecurityException. 137 * </ol> 138 * 139 * NOTE: This is an implementation of the SecurityManager.currentClassLoader 140 * method that uses StackWalker. SecurityManager.currentClassLoader 141 * has been removed from SE. This is a temporary workaround which is 142 * only needed while applets are still supported. 143 * 144 * @return the class loader of the most recent occurrence on the stack 145 * of a method from a class defined using a non-system class 146 * loader. 147 */ 148 private static ClassLoader currentClassLoader() { 149 StackFrame f = 150 walker.walk(s -> s.takeWhile(AppletSecurity::isNonPrivileged) 151 .filter(AppletSecurity::isNonSystemFrame) 152 .findFirst()) 153 .orElse(null); 154 155 SecurityManager sm = System.getSecurityManager(); 156 if (f != null && sm != null) { 157 try { 158 sm.checkPermission(new AllPermission()); 159 } catch (SecurityException se) { 160 return f.getDeclaringClass().getClassLoader(); 161 } 162 } 163 return null; 164 } 165 166 /** 167 * Returns true if the StackFrame is not AccessController.doPrivileged. 168 */ 169 private static boolean isNonPrivileged(StackFrame f) { 170 // possibly other doPrivileged variants 171 Class<?> c = f.getDeclaringClass(); 172 return c == AccessController.class && 173 f.getMethodName().equals("doPrivileged"); 174 } 175 176 /** 177 * Returns true if the StackFrame is not from a class defined by the 178 * system class loader or one of its ancestors. 179 */ 180 private static boolean isNonSystemFrame(StackFrame f) { 181 ClassLoader loader = ClassLoader.getSystemClassLoader(); 182 ClassLoader ld = f.getDeclaringClass().getClassLoader(); 183 if (ld == null || ld == loader) return false; 184 185 while ((loader = loader.getParent()) != null) { 186 if (ld == loader) 187 return false; 188 } 189 return true; 190 } 191 192 /** 193 * get the current (first) instance of an AppletClassLoader on the stack. 194 */ 195 private AppletClassLoader currentAppletClassLoader() 196 { 197 // try currentClassLoader first 198 ClassLoader loader = currentClassLoader(); 199 200 if ((loader == null) || (loader instanceof AppletClassLoader)) 201 return (AppletClassLoader)loader; 202 203 // if that fails, get all the classes on the stack and check them. 204 Class<?>[] context = getClassContext(); 205 for (int i = 0; i < context.length; i++) { 206 loader = context[i].getClassLoader(); 207 if (loader instanceof AppletClassLoader) 208 return (AppletClassLoader)loader; 209 } 210 211 /* 212 * fix bug # 6433620 the logic here is : try to find URLClassLoader from 213 * class context, check its AccessControlContext to see if 214 * AppletClassLoader is in stack when it's created. for this kind of 215 * URLClassLoader, return the AppContext associated with the 216 * AppletClassLoader. 217 */ 218 for (int i = 0; i < context.length; i++) { 219 final ClassLoader currentLoader = context[i].getClassLoader(); 220 221 if (currentLoader instanceof URLClassLoader) { 222 URLClassLoader ld = (URLClassLoader)currentLoader; 223 loader = AccessController.doPrivileged( 224 new PrivilegedAction<ClassLoader>() { 225 public ClassLoader run() { 226 227 AccessControlContext acc = null; 228 ProtectionDomain[] pds = null; 229 230 try { 231 acc = JNUCLA.getAccessControlContext(ld); 232 if (acc == null) { 233 return null; 234 } 235 236 pds = JSA.getProtectDomains(acc); 237 if (pds == null) { 238 return null; 239 } 240 } catch (Exception e) { 241 throw new UnsupportedOperationException(e); 242 } 243 244 for (int i=0; i<pds.length; i++) { 245 ClassLoader cl = pds[i].getClassLoader(); 246 247 if (cl instanceof AppletClassLoader) { 248 return cl; 249 } 250 } 251 252 return null; 253 } 254 }); 255 256 if (loader != null) { 257 return (AppletClassLoader) loader; 258 } 259 } 260 } 261 262 // if that fails, try the context class loader 263 loader = Thread.currentThread().getContextClassLoader(); 264 if (loader instanceof AppletClassLoader) 265 return (AppletClassLoader)loader; 266 267 // no AppletClassLoaders on the stack 268 return (AppletClassLoader)null; 269 } 270 271 /** 272 * Returns true if this threadgroup is in the applet's own thread 273 * group. This will return false if there is no current class 274 * loader. 275 */ 276 protected boolean inThreadGroup(ThreadGroup g) { 277 if (currentAppletClassLoader() == null) 278 return false; 279 else 280 return getThreadGroup().parentOf(g); 281 } 282 283 /** 284 * Returns true of the threadgroup of thread is in the applet's 285 * own threadgroup. 286 */ 287 protected boolean inThreadGroup(Thread thread) { 288 return inThreadGroup(thread.getThreadGroup()); 289 } 290 291 /** 292 * Applets are not allowed to manipulate threads outside 293 * applet thread groups. However a terminated thread no longer belongs 294 * to any group. 295 */ 296 public void checkAccess(Thread t) { 297 /* When multiple applets is reloaded simultaneously, there will be 298 * multiple invocations to this method from plugin's SecurityManager. 299 * This method should not be synchronized to avoid deadlock when 300 * a page with multiple applets is reloaded 301 */ 302 if ((t.getState() != Thread.State.TERMINATED) && !inThreadGroup(t)) { 303 checkPermission(SecurityConstants.MODIFY_THREAD_PERMISSION); 304 } 305 } 306 307 private boolean inThreadGroupCheck = false; 308 309 /** 310 * Applets are not allowed to manipulate thread groups outside 311 * applet thread groups. 312 */ 313 public synchronized void checkAccess(ThreadGroup g) { 314 if (inThreadGroupCheck) { 315 // if we are in a recursive check, it is because 316 // inThreadGroup is calling appletLoader.getThreadGroup 317 // in that case, only do the super check, as appletLoader 318 // has a begin/endPrivileged 319 checkPermission(SecurityConstants.MODIFY_THREADGROUP_PERMISSION); 320 } else { 321 try { 322 inThreadGroupCheck = true; 323 if (!inThreadGroup(g)) { 324 checkPermission(SecurityConstants.MODIFY_THREADGROUP_PERMISSION); 325 } 326 } finally { 327 inThreadGroupCheck = false; 328 } 329 } 330 } 331 332 333 /** 334 * Throws a {@code SecurityException} if the 335 * calling thread is not allowed to access the package specified by 336 * the argument. 337 * <p> 338 * This method is used by the {@code loadClass} method of class 339 * loaders. 340 * <p> 341 * The {@code checkPackageAccess} method for class 342 * {@code SecurityManager} calls 343 * {@code checkPermission} with the 344 * {@code RuntimePermission("accessClassInPackage."+ pkgname)} 345 * permission. 346 * 347 * @param pkgname the package name. 348 * @exception SecurityException if the caller does not have 349 * permission to access the specified package. 350 * @see java.lang.ClassLoader#loadClass(java.lang.String, boolean) 351 */ 352 public void checkPackageAccess(final String pkgname) { 353 354 // first see if the VM-wide policy allows access to this package 355 super.checkPackageAccess(pkgname); 356 357 // now check the list of restricted packages 358 for (Iterator<String> iter = restrictedPackages.iterator(); iter.hasNext();) 359 { 360 String pkg = iter.next(); 361 362 // Prevent matching "sun" and "sunir" even if they 363 // starts with similar beginning characters 364 // 365 if (pkgname.equals(pkg) || pkgname.startsWith(pkg + ".")) 366 { 367 checkPermission(new java.lang.RuntimePermission 368 ("accessClassInPackage." + pkgname)); 369 } 370 } 371 } 372 373 /** 374 * Returns the thread group of the applet. We consult the classloader 375 * if there is one. 376 */ 377 public ThreadGroup getThreadGroup() { 378 /* If any applet code is on the execution stack, we return 379 that applet's ThreadGroup. Otherwise, we use the default 380 behavior. */ 381 AppletClassLoader appletLoader = currentAppletClassLoader(); 382 ThreadGroup loaderGroup = (appletLoader == null) ? null 383 : appletLoader.getThreadGroup(); 384 if (loaderGroup != null) { 385 return loaderGroup; 386 } else { 387 return super.getThreadGroup(); 388 } 389 } // getThreadGroup() 390 391 /** 392 * Get the AppContext corresponding to the current context. 393 * The default implementation returns null, but this method 394 * may be overridden by various SecurityManagers 395 * (e.g. AppletSecurity) to index AppContext objects by the 396 * calling context. 397 * 398 * @return the AppContext corresponding to the current context. 399 * @see sun.awt.AppContext 400 * @see java.lang.SecurityManager 401 * @since 1.2.1 402 */ 403 public AppContext getAppContext() { 404 AppletClassLoader appletLoader = currentAppletClassLoader(); 405 406 if (appletLoader == null) { 407 return null; 408 } else { 409 AppContext context = appletLoader.getAppContext(); 410 411 // context == null when some thread in applet thread group 412 // has not been destroyed in AppContext.dispose() 413 if (context == null) { 414 throw new SecurityException("Applet classloader has invalid AppContext"); 415 } 416 417 return context; 418 } 419 } 420 421 } // class AppletSecurity