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