changeset 484:0933d8b8547a

6907662: System clipboard should ensure access restrictions Reviewed-by: alexp
author denis
date Fri, 28 Jan 2011 20:01:23 +0300
parents c63bf13943c1
children 1da22d47056e
files src/share/classes/java/awt/AWTEvent.java src/share/classes/java/awt/Component.java src/share/classes/java/awt/EventDispatchThread.java src/share/classes/java/awt/EventQueue.java src/share/classes/java/awt/MenuComponent.java src/share/classes/java/awt/TrayIcon.java src/share/classes/java/security/AccessControlContext.java src/share/classes/javax/swing/Timer.java src/share/classes/javax/swing/TransferHandler.java src/share/classes/sun/awt/AWTAccessor.java src/share/classes/sun/misc/JavaSecurityAccess.java src/share/classes/sun/misc/SharedSecrets.java
diffstat 12 files changed, 485 insertions(+), 11 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/java/awt/AWTEvent.java	Tue Dec 28 10:31:27 2010 -0800
+++ b/src/share/classes/java/awt/AWTEvent.java	Fri Jan 28 20:01:23 2011 +0300
@@ -33,6 +33,12 @@
 import java.util.logging.Logger;
 import java.util.logging.Level;
 
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.io.ObjectInputStream;
+import java.io.IOException;
+import sun.awt.AWTAccessor;
+
 /**
  * The root event class for all AWT events.
  * This class and its subclasses supercede the original
@@ -97,10 +103,33 @@
      */
     protected boolean consumed = false;
 
+    /*
+     * The event's AccessControlContext.
+     */
+    private transient volatile AccessControlContext acc =
+        AccessController.getContext();
+
+    /*
+     * Returns the acc this event was constructed with.
+     */
+    final AccessControlContext getAccessControlContext() {
+        if (acc == null) {
+            throw new SecurityException("AWTEvent is missing AccessControlContext");
+        }
+            return acc;
+        }
+
     transient boolean focusManagerIsDispatching = false;
     transient boolean isPosted;
 
     /**
+     * Indicates whether this AWTEvent was generated by the system as
+     * opposed to by user code.
+     */
+    private transient boolean isSystemGenerated;
+
+
+    /**
      * The event mask for selecting component events.
      */
     public final static long COMPONENT_EVENT_MASK = 0x01;
@@ -230,6 +259,19 @@
         if (!GraphicsEnvironment.isHeadless()) {
             initIDs();
         }
+        AWTAccessor.setAWTEventAccessor(new AWTAccessor.AWTEventAccessor() {
+                public void setSystemGenerated(AWTEvent ev) {
+                    ev.isSystemGenerated = true;
+                }
+
+                public boolean isSystemGenerated(AWTEvent ev) {
+                    return ev.isSystemGenerated;
+                }
+
+                public AccessControlContext getAccessControlContext(AWTEvent ev) {
+                    return ev.getAccessControlContext();
+                }
+        });
     }
 
     private static synchronized Field get_InputEvent_CanAccessSystemClipboard() {
@@ -564,4 +606,11 @@
             }
         }
     }
+
+    private void readObject(ObjectInputStream in) 
+        throws ClassNotFoundException, IOException
+    {
+        this.acc = AccessController.getContext();
+        in.defaultReadObject();
+    }
 } // class AWTEvent
--- a/src/share/classes/java/awt/Component.java	Tue Dec 28 10:31:27 2010 -0800
+++ b/src/share/classes/java/awt/Component.java	Fri Jan 28 20:01:23 2011 +0300
@@ -58,9 +58,11 @@
 import java.lang.reflect.Method;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
+import java.security.AccessControlContext;
 import javax.accessibility.*;
 import java.util.logging.*;
 import java.applet.Applet;
+import sun.awt.AWTAccessor;
 
 import sun.security.action.GetPropertyAction;
 import sun.awt.AppContext;
@@ -451,6 +453,12 @@
     static final Object LOCK = new AWTTreeLock();
     static class AWTTreeLock {}
 
+    /*
+     * The component's AccessControlContext.
+     */
+    private transient volatile AccessControlContext acc =
+        AccessController.getContext();
+
     /**
      * Minimum size.
      * (This field perhaps should have been transient).
@@ -641,6 +649,16 @@
         return changeSupportLock;
     }
 
+    /*
+     * Returns the acc this component was constructed with.
+     */
+    final AccessControlContext getAccessControlContext() {
+        if (acc == null) {
+            throw new SecurityException("Component is missing AccessControlContext");
+        }
+        return acc;
+    }
+
     boolean isPacked = false;
 
     /**
@@ -778,6 +796,16 @@
             }
     }
 
+    static {
+        AWTAccessor.setComponentAccessor(new AWTAccessor.ComponentAccessor() {
+                public AccessControlContext getAccessControlContext(Component comp) {
+                    return comp.getAccessControlContext();
+                }
+
+            });
+    }
+
+
     /**
      * Constructs a new component. Class <code>Component</code> can be
      * extended directly to create a lightweight component that does not
@@ -8317,6 +8345,8 @@
     {
         changeSupportLock = new Object();
 
+        acc = AccessController.getContext();
+
         s.defaultReadObject();
 
         appContext = AppContext.getAppContext();
--- a/src/share/classes/java/awt/EventDispatchThread.java	Tue Dec 28 10:31:27 2010 -0800
+++ b/src/share/classes/java/awt/EventDispatchThread.java	Fri Jan 28 20:01:23 2011 +0300
@@ -284,10 +284,7 @@
                           // Threads in the AppContext
 
         }
-        // Can get and throw only unchecked exceptions
-        catch (RuntimeException e) {
-            processException(e, modalFiltersCount > 0);
-        } catch (Error e) {
+        catch (Throwable e) {
             processException(e, modalFiltersCount > 0);
         }
         return true;
--- a/src/share/classes/java/awt/EventQueue.java	Tue Dec 28 10:31:27 2010 -0800
+++ b/src/share/classes/java/awt/EventQueue.java	Fri Jan 28 20:01:23 2011 +0300
@@ -43,6 +43,12 @@
 import sun.awt.PeerEvent;
 import sun.awt.SunToolkit;
 
+import java.security.AccessControlContext;
+import java.security.ProtectionDomain;
+
+import sun.misc.SharedSecrets;
+import sun.misc.JavaSecurityAccess;
+
 /**
  * <code>EventQueue</code> is a platform-independent class
  * that queues events, both from the underlying peer classes
@@ -554,6 +560,9 @@
         return null;
     }
 
+    private static final JavaSecurityAccess javaSecurityAccess =
+        SharedSecrets.getJavaSecurityAccess();
+
     /**
      * Dispatches an event. The manner in which the event is
      * dispatched depends upon the type of the event and the
@@ -592,13 +601,49 @@
      * @throws NullPointerException if <code>event</code> is <code>null</code>
      * @since           1.2
      */
-    protected void dispatchEvent(AWTEvent event) {
+    protected void dispatchEvent(final AWTEvent event) {
+        final Object src = event.getSource();
+        final PrivilegedAction<Void> action = new PrivilegedAction<Void>() {
+            public Void run() {
+                dispatchEventImpl(event, src);
+                return null;
+            }
+        };
+
+        final AccessControlContext stack = AccessController.getContext();
+        final AccessControlContext srcAcc = getAccessControlContextFrom(src);
+        final AccessControlContext eventAcc = event.getAccessControlContext();
+        if (srcAcc == null) {
+            javaSecurityAccess.doIntersectionPrivilege(action, stack, eventAcc);
+        } else {
+            javaSecurityAccess.doIntersectionPrivilege(
+                new PrivilegedAction<Void>() {
+                    public Void run() {
+                        javaSecurityAccess.doIntersectionPrivilege(action, eventAcc);
+                        return null;
+                    }
+                }, stack, srcAcc);
+        }
+    }
+
+    private static AccessControlContext getAccessControlContextFrom(Object src) {
+        return src instanceof Component ?
+            ((Component)src).getAccessControlContext() :
+            src instanceof MenuComponent ?
+                ((MenuComponent)src).getAccessControlContext() :
+                src instanceof TrayIcon ?
+                    ((TrayIcon)src).getAccessControlContext() :
+                    null;
+    }
+
+    /**
+     * Called from dispatchEvent() under a correct AccessControlContext  
+     */
+    private void dispatchEventImpl(final AWTEvent event, final Object src) {
         event.isPosted = true;
-        Object src = event.getSource();
         if (event instanceof ActiveEvent) {
             // This could become the sole method of dispatching in time.
             setCurrentEventAndMostRecentTimeImpl(event);
-
             ((ActiveEvent)event).dispatch();
         } else if (src instanceof Component) {
             ((Component)src).dispatchEvent(event);
--- a/src/share/classes/java/awt/MenuComponent.java	Tue Dec 28 10:31:27 2010 -0800
+++ b/src/share/classes/java/awt/MenuComponent.java	Fri Jan 28 20:01:23 2011 +0300
@@ -32,6 +32,9 @@
 import sun.awt.SunToolkit;
 import javax.accessibility.*;
 
+import java.security.AccessControlContext;
+import java.security.AccessController;
+
 /**
  * The abstract class <code>MenuComponent</code> is the superclass
  * of all menu-related components. In this respect, the class
@@ -99,6 +102,23 @@
     boolean newEventsOnly = false;
 
     /*
+     * The menu's AccessControlContext.
+     */
+    private transient volatile AccessControlContext acc =
+            AccessController.getContext();
+    
+    /*
+     * Returns the acc this menu component was constructed with.
+     */
+    final AccessControlContext getAccessControlContext() {
+        if (acc == null) {
+            throw new SecurityException(
+                    "MenuComponent is missing AccessControlContext");
+        }
+        return acc;
+    }
+
+    /*
      * Internal constants for serialization.
      */
     final static String actionListenerK = Component.actionListenerK;
@@ -385,6 +405,9 @@
         throws ClassNotFoundException, IOException, HeadlessException
     {
         GraphicsEnvironment.checkHeadless();
+
+        acc = AccessController.getContext();
+
         s.defaultReadObject();
 
         appContext = AppContext.getAppContext();
--- a/src/share/classes/java/awt/TrayIcon.java	Tue Dec 28 10:31:27 2010 -0800
+++ b/src/share/classes/java/awt/TrayIcon.java	Fri Jan 28 20:01:23 2011 +0300
@@ -39,6 +39,8 @@
 import sun.awt.AppContext;
 import sun.awt.SunToolkit;
 import java.util.EventObject;
+import java.security.AccessControlContext;
+import java.security.AccessController;
 
 /**
  * A <code>TrayIcon</code> object represents a tray icon that can be
@@ -89,6 +91,7 @@
  * @author Anton Tarasov
  */
 public class TrayIcon {
+
     private Image image;
     private String tooltip;
     private PopupMenu popup;
@@ -102,6 +105,24 @@
     transient MouseMotionListener mouseMotionListener;
     transient ActionListener actionListener;
 
+    /*
+     * The tray icon's AccessControlContext.
+     *
+     * Unlike the acc in Component, this field is made final
+     * because TrayIcon is not serializable.
+     */
+    private final AccessControlContext acc = AccessController.getContext();
+    
+    /*
+     * Returns the acc this tray icon was constructed with.
+     */
+    final AccessControlContext getAccessControlContext() {
+        if (acc == null) {
+            throw new SecurityException("TrayIcon is missing AccessControlContext");
+        }
+        return acc;
+    }
+
     static {
         Toolkit.loadLibraries();
         if (!GraphicsEnvironment.isHeadless()) {
--- a/src/share/classes/java/security/AccessControlContext.java	Tue Dec 28 10:31:27 2010 -0800
+++ b/src/share/classes/java/security/AccessControlContext.java	Fri Jan 28 20:01:23 2011 +0300
@@ -29,6 +29,9 @@
 import java.util.List;
 import sun.security.util.Debug;
 import sun.security.util.SecurityConstants;
+import sun.misc.JavaSecurityAccess;
+import sun.misc.SharedSecrets;
+
 
 /**
  * An AccessControlContext is used to make system resource access decisions
@@ -87,6 +90,36 @@
     private static boolean debugInit = false;
     private static Debug debug = null;
 
+    static {
+        // Set up JavaSecurityAccess in SharedSecrets
+        SharedSecrets.setJavaSecurityAccess(
+            new JavaSecurityAccess() {
+                public <T> T doIntersectionPrivilege(
+                    PrivilegedAction<T> action,
+                    final AccessControlContext stack,
+                    final AccessControlContext context)
+                {
+                    if (action == null) {
+                        throw new NullPointerException();
+                    }
+                    return AccessController.doPrivileged(
+                        action,
+                        new AccessControlContext(
+                            stack.getContext(), context).optimize()
+                    );
+                }
+
+                public <T> T doIntersectionPrivilege(
+                    PrivilegedAction<T> action,
+                    AccessControlContext context)
+                {
+                    return doIntersectionPrivilege(action,
+                        AccessController.getContext(), context);
+                }
+            }
+       );
+    }
+
     static Debug getDebug()
     {
         if (debugInit)
@@ -194,6 +227,24 @@
     }
 
     /**
+     * Constructor for JavaSecurityAccess.doIntersectionPrivilege()
+     */
+    AccessControlContext(ProtectionDomain[] context,
+                         AccessControlContext privilegedContext)
+    {
+        this.context = context;
+        this.privilegedContext = privilegedContext;
+        this.isPrivileged = true;
+    }
+
+    /**
+     * Returns this context's context.
+     */
+    ProtectionDomain[] getContext() {
+        return context;
+    }
+
+    /**
      * Returns true if this context is privileged.
      */
     boolean isPrivileged()
--- a/src/share/classes/javax/swing/Timer.java	Tue Dec 28 10:31:27 2010 -0800
+++ b/src/share/classes/javax/swing/Timer.java	Fri Jan 28 20:01:23 2011 +0300
@@ -35,6 +35,10 @@
 import java.awt.*;
 import java.awt.event.*;
 import java.io.Serializable;
+import java.io.*;
+import java.security.AccessControlContext;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
 import javax.swing.event.EventListenerList;
 
 
@@ -174,6 +178,23 @@
 
     private transient final Lock lock = new ReentrantLock();
 
+    /*
+     * The timer's AccessControlContext.
+     */
+     private transient volatile AccessControlContext acc =
+            AccessController.getContext();
+
+    /**
+      * Returns the acc this timer was constructed with.
+      */
+     final AccessControlContext getAccessControlContext() {
+       if (acc == null) {
+           throw new SecurityException(
+                   "Timer is missing AccessControlContext");
+       }
+       return acc;
+     }
+
     // This field is maintained by TimerQueue.
     // eventQueued can also be reset by the TimerQueue, but will only ever
     // happen in applet case when TimerQueues thread is destroyed.
@@ -191,7 +212,7 @@
      *
      * @param delay milliseconds for the initial and between-event delay
      * @param listener  an initial listener; can be <code>null</code>
-     *
+
      * @see #addActionListener
      * @see #setInitialDelay
      * @see #setRepeats
@@ -208,7 +229,6 @@
         }
     }
 
-
     /**
      * DoPostEvent is a runnable class that fires actionEvents to
      * the listeners on the EventDispatchThread, via invokeLater.
@@ -589,7 +609,12 @@
 
     void post() {
         if (notify.compareAndSet(false, true) || !coalesce) {
-            SwingUtilities.invokeLater(doPostEvent);
+            AccessController.doPrivileged(new PrivilegedAction<Void>() {
+                public Void run() {
+                    SwingUtilities.invokeLater(doPostEvent);
+                    return null;
+                 }
+            }, getAccessControlContext());
         }
     }
 
@@ -611,4 +636,11 @@
         timer.actionCommand = actionCommand;
         return timer;
     }
+
+     private void readObject(ObjectInputStream in) 
+        throws ClassNotFoundException, IOException
+     {
+        this.acc = AccessController.getContext();
+        in.defaultReadObject();
+     }
 }
--- a/src/share/classes/javax/swing/TransferHandler.java	Tue Dec 28 10:31:27 2010 -0800
+++ b/src/share/classes/javax/swing/TransferHandler.java	Fri Jan 28 20:01:23 2011 +0300
@@ -41,6 +41,16 @@
 import sun.awt.AppContext;
 import sun.swing.*;
 
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+import java.security.AccessControlContext;
+import java.security.ProtectionDomain;
+import sun.misc.SharedSecrets;
+import sun.misc.JavaSecurityAccess;
+
+import sun.awt.AWTAccessor;
+
 /**
  * This class is used to handle the transfer of a <code>Transferable</code>
  * to and from Swing components.  The <code>Transferable</code> is used to
@@ -1640,7 +1650,37 @@
             return true;
         }
 
-        public void actionPerformed(ActionEvent e) {
+        private static final JavaSecurityAccess javaSecurityAccess =
+            SharedSecrets.getJavaSecurityAccess();
+
+        public void actionPerformed(final ActionEvent e) {
+            final Object src = e.getSource();
+
+            final PrivilegedAction<Void> action = new PrivilegedAction<Void>() {
+                public Void run() {
+                    actionPerformedImpl(e);
+                    return null;
+                }
+            };
+
+            final AccessControlContext stack = AccessController.getContext();
+            final AccessControlContext srcAcc = AWTAccessor.getComponentAccessor().getAccessControlContext((Component)src);
+            final AccessControlContext eventAcc = AWTAccessor.getAWTEventAccessor().getAccessControlContext(e);
+
+                if (srcAcc == null) {
+                    javaSecurityAccess.doIntersectionPrivilege(action, stack, eventAcc);
+                } else {
+                    javaSecurityAccess.doIntersectionPrivilege(
+                        new PrivilegedAction<Void>() {
+                            public Void run() {
+                                javaSecurityAccess.doIntersectionPrivilege(action, eventAcc);
+                                return null;
+                             }
+                    }, stack, srcAcc);
+                }
+        }
+
+        private void actionPerformedImpl(ActionEvent e) {
             Object src = e.getSource();
             if (src instanceof JComponent) {
                 JComponent c = (JComponent) src;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/awt/AWTAccessor.java	Fri Jan 28 20:01:23 2011 +0300
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.awt;
+
+import java.awt.*;
+import java.awt.event.InputEvent;
+import java.awt.geom.Point2D;
+import java.awt.image.BufferedImage;
+
+import sun.misc.Unsafe;
+import java.awt.peer.ComponentPeer;
+
+import java.security.AccessController;
+import java.security.AccessControlContext;
+
+/**
+ * The AWTAccessor utility class.
+ * The main purpose of this class is to enable accessing
+ * private and package-private fields of classes from
+ * different classes/packages. See sun.misc.SharedSecretes
+ * for another example.
+ */
+public final class AWTAccessor {
+
+    private static final Unsafe unsafe = Unsafe.getUnsafe();
+
+    /*
+     * We don't need any objects of this class.
+     * It's rather a collection of static methods
+     * and interfaces.
+     */
+    private AWTAccessor() {
+    }
+
+    /*
+     * An interface of accessor for the java.awt.Component class.
+     */
+    public interface ComponentAccessor {
+        /*
+         * Returns the acc this component was constructed with.
+         */
+        AccessControlContext getAccessControlContext(Component comp);
+    }
+
+    /*
+     * An accessor for the AWTEvent class.
+     */
+    public interface AWTEventAccessor {
+        /**
+         * Sets the flag on this AWTEvent indicating that it was
+         * generated by the system.
+         */
+        void setSystemGenerated(AWTEvent ev);
+
+        /**
+         * Indicates whether this AWTEvent was generated by the system.
+         */
+        boolean isSystemGenerated(AWTEvent ev);
+
+
+        /*
+         * Returns the acc this event was constructed with.
+         */
+        AccessControlContext getAccessControlContext(AWTEvent ev);
+
+    }
+
+    /*
+     * Accessor instances are initialized in the static initializers of
+     * corresponding AWT classes by using setters defined below.
+     */
+    private static ComponentAccessor componentAccessor;
+    private static AWTEventAccessor awtEventAccessor;
+
+    /*
+     * Set an accessor object for the java.awt.Component class.
+     */
+    public static void setComponentAccessor(ComponentAccessor ca) {
+        componentAccessor = ca;
+    }
+
+    /*
+     * Retrieve the accessor object for the java.awt.Component class.
+     */
+    public static ComponentAccessor getComponentAccessor() {
+        if (componentAccessor == null) {
+            unsafe.ensureClassInitialized(Component.class);
+        }
+
+        return componentAccessor;
+    }
+
+    /*
+     * Set an accessor object for the java.awt.AWTEvent class.
+     */
+    public static void setAWTEventAccessor(AWTEventAccessor aea) {
+        awtEventAccessor = aea;
+    }
+
+    /*
+     * Retrieve the accessor object for the java.awt.AWTEvent class.
+     */
+    public static AWTEventAccessor getAWTEventAccessor() {
+        if (awtEventAccessor == null) {
+            unsafe.ensureClassInitialized(AWTEvent.class);
+        }
+        return awtEventAccessor;
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/sun/misc/JavaSecurityAccess.java	Fri Jan 28 20:01:23 2011 +0300
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.misc;
+
+import java.security.AccessControlContext;
+import java.security.PrivilegedAction;
+
+public interface JavaSecurityAccess {
+
+    <T> T doIntersectionPrivilege(PrivilegedAction<T> action,
+                                  AccessControlContext stack,
+                                  AccessControlContext context);
+
+    <T> T doIntersectionPrivilege(PrivilegedAction<T> action,
+                                  AccessControlContext context);
+
+}
--- a/src/share/classes/sun/misc/SharedSecrets.java	Tue Dec 28 10:31:27 2010 -0800
+++ b/src/share/classes/sun/misc/SharedSecrets.java	Fri Jan 28 20:01:23 2011 +0300
@@ -31,6 +31,8 @@
 import java.io.FileDescriptor;
 import java.security.ProtectionDomain;
 
+import java.security.AccessController;
+
 /** A repository of "shared secrets", which are a mechanism for
     calling implementation-private methods in another package without
     using reflection. A package-private class implements a public
@@ -49,6 +51,7 @@
     private static JavaNetAccess javaNetAccess;
     private static JavaIOFileDescriptorAccess javaIOFileDescriptorAccess;
     private static JavaSecurityProtectionDomainAccess javaSecurityProtectionDomainAccess;
+    private static JavaSecurityAccess javaSecurityAccess;
 
     public static JavaUtilJarAccess javaUtilJarAccess() {
         if (javaUtilJarAccess == null) {
@@ -124,4 +127,15 @@
 
         return javaSecurityProtectionDomainAccess;
     }
+
+    public static void setJavaSecurityAccess(JavaSecurityAccess jsa) {
+        javaSecurityAccess = jsa;
+    }
+
+    public static JavaSecurityAccess getJavaSecurityAccess() {
+        if (javaSecurityAccess == null) {
+            unsafe.ensureClassInitialized(AccessController.class);
+        }
+        return javaSecurityAccess;
+    }
 }