VMAccessController.java 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. /* VMAccessController.java -- VM-specific access controller methods.
  2. Copyright (C) 2004, 2005, 2006, 2010 Free Software Foundation, Inc.
  3. This program is free software; you can redistribute it and/or modify
  4. it under the terms of the GNU General Public License as published by
  5. the Free Software Foundation; either version 2, or (at your option)
  6. any later version.
  7. This program is distributed in the hope that it will be useful, but
  8. WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  10. General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; see the file COPYING. If not, write to the
  13. Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  14. 02110-1301 USA.
  15. Linking this library statically or dynamically with other modules is
  16. making a combined work based on this library. Thus, the terms and
  17. conditions of the GNU General Public License cover the whole
  18. combination.
  19. As a special exception, the copyright holders of this library give you
  20. permission to link this library with independent modules to produce an
  21. executable, regardless of the license terms of these independent
  22. modules, and to copy and distribute the resulting executable under
  23. terms of your choice, provided that you also meet, for each linked
  24. independent module, the terms and conditions of the license of that
  25. module. An independent module is a module which is not derived from
  26. or based on this library. If you modify this library, you may extend
  27. this exception to your version of the library, but you are not
  28. obligated to do so. If you do not wish to do so, delete this
  29. exception statement from your version. */
  30. package java.security;
  31. import java.util.HashSet;
  32. import java.util.LinkedList;
  33. final class VMAccessController
  34. {
  35. // Fields.
  36. // -------------------------------------------------------------------------
  37. /**
  38. * And we return this all-permissive context to ensure that privileged
  39. * methods called from getContext succeed.
  40. */
  41. private static final AccessControlContext DEFAULT_CONTEXT;
  42. static
  43. {
  44. CodeSource source = new CodeSource(null, null);
  45. Permissions permissions = new Permissions();
  46. permissions.add(new AllPermission());
  47. ProtectionDomain[] domain = new ProtectionDomain[] {
  48. new ProtectionDomain(source, permissions, null, null)
  49. };
  50. DEFAULT_CONTEXT = new AccessControlContext(domain);
  51. }
  52. private static final boolean DEBUG = gnu.classpath.Configuration.DEBUG;
  53. private static void debug(String msg)
  54. {
  55. System.err.print(">>> VMAccessController: ");
  56. System.err.println(msg);
  57. }
  58. // Constructors.
  59. // -------------------------------------------------------------------------
  60. private VMAccessController() { }
  61. // Class methods.
  62. // -------------------------------------------------------------------------
  63. /**
  64. * Relate a class (which should be an instance of {@link PrivilegedAction}
  65. * with an access control context. This method is used by {@link
  66. * AccessController#doPrivileged(java.security.PrivilegedAction,java.security.AccessControlContext)}
  67. * to set up the context that will be returned by {@link #getContext()}.
  68. * This method relates the class to the current thread, so contexts
  69. * pushed from one thread will not be available to another.
  70. *
  71. * @param acc The access control context.
  72. */
  73. static void pushContext (AccessControlContext acc)
  74. {
  75. // Can't really do anything while the VM is initializing.
  76. VMAccessControlState state = VMAccessControlState.getThreadState();
  77. if (state == null)
  78. return;
  79. if (DEBUG)
  80. debug("pushing " + acc);
  81. LinkedList stack = state.getContexts();
  82. stack.addFirst(acc);
  83. }
  84. /**
  85. * Removes the relation of a class to an {@link AccessControlContext}.
  86. * This method is used by {@link AccessController} when exiting from a
  87. * call to {@link
  88. * AccessController#doPrivileged(java.security.PrivilegedAction,java.security.AccessControlContext)}.
  89. */
  90. static void popContext()
  91. {
  92. // Can't really do anything while the VM is initializing.
  93. VMAccessControlState state = VMAccessControlState.getThreadState();
  94. if (state == null)
  95. return;
  96. if (DEBUG)
  97. debug("popping context");
  98. // Stack should never be null, nor should it be empty, if this method
  99. // and its counterpart has been called properly.
  100. LinkedList stack = state.getContexts();
  101. if (!stack.isEmpty())
  102. {
  103. stack.removeFirst();
  104. }
  105. else if (DEBUG)
  106. {
  107. debug("no stack during pop?????");
  108. }
  109. }
  110. /**
  111. * Examine the method stack of the currently running thread, and create
  112. * an {@link AccessControlContext} filled in with the appropriate {@link
  113. * ProtectionDomain} objects given this stack.
  114. *
  115. * @return The context.
  116. */
  117. static AccessControlContext getContext()
  118. {
  119. // If the VM is initializing return the all-permissive context
  120. // so that any security checks succeed.
  121. VMAccessControlState state = VMAccessControlState.getThreadState();
  122. if (state == null)
  123. return DEFAULT_CONTEXT;
  124. // If we are already in getContext, but called a method that needs
  125. // a permission check, return the all-permissive context so methods
  126. // called from here succeed.
  127. //
  128. // XXX is this necessary? We should verify if there are any calls in
  129. // the stack below this method that require permission checks.
  130. if (state.isInGetContext())
  131. {
  132. if (DEBUG)
  133. debug("already in getContext");
  134. return DEFAULT_CONTEXT;
  135. }
  136. state.setInGetContext(true);
  137. Object[] stack = getStack();
  138. Class[] classes = (Class[]) stack[0];
  139. boolean privileged = ((Boolean) stack[1]).booleanValue();
  140. if (DEBUG)
  141. debug("got trace of length " + classes.length);
  142. HashSet domains = new HashSet();
  143. HashSet seenDomains = new HashSet();
  144. AccessControlContext context = null;
  145. // We walk down the stack, adding each ProtectionDomain for each
  146. // class in the call stack. If we reach a call to doPrivileged,
  147. // we don't add any more stack frames. We skip the first three stack
  148. // frames, since they comprise the calls to getStack, getContext,
  149. // and AccessController.getContext.
  150. for (int i = 3; i < classes.length; i++)
  151. {
  152. Class clazz = classes[i];
  153. ClassLoader loader = clazz.getClassLoader();
  154. if (DEBUG)
  155. {
  156. debug("checking " + clazz);
  157. // subject to getClassLoader RuntimePermission
  158. debug("loader = " + loader);
  159. }
  160. if (privileged && i == classes.length - 2)
  161. {
  162. // If there was a call to doPrivileged with a supplied context,
  163. // return that context. If using JAAS doAs*, it should be
  164. // a context with a SubjectDomainCombiner
  165. LinkedList l = state.getContexts();
  166. if (!l.isEmpty())
  167. context = (AccessControlContext) l.getFirst();
  168. }
  169. // subject to getProtectionDomain RuntimePermission
  170. ProtectionDomain domain = clazz.getProtectionDomain();
  171. if (domain == null)
  172. continue;
  173. if (seenDomains.contains(domain))
  174. continue;
  175. seenDomains.add(domain);
  176. // Create a static snapshot of this domain, which may change over time
  177. // if the current policy changes.
  178. domains.add(new ProtectionDomain(domain.getCodeSource(),
  179. domain.getPermissions(),
  180. loader, null));
  181. }
  182. if (DEBUG)
  183. debug("created domains: " + domains);
  184. ProtectionDomain[] result = (ProtectionDomain[])
  185. domains.toArray(new ProtectionDomain[domains.size()]);
  186. if (context != null)
  187. {
  188. DomainCombiner dc = context.getDomainCombiner ();
  189. // If the supplied context had no explicit DomainCombiner, use
  190. // our private version, which computes the intersection of the
  191. // context's domains with the derived set.
  192. if (dc == null)
  193. context = new AccessControlContext
  194. (IntersectingDomainCombiner.SINGLETON.combine
  195. (result, context.getProtectionDomains ()));
  196. // Use the supplied DomainCombiner. This should be secure,
  197. // because only trusted code may create an
  198. // AccessControlContext with a custom DomainCombiner.
  199. else
  200. context = new AccessControlContext (result, context, dc);
  201. }
  202. // No context was supplied. Return the derived one.
  203. else
  204. context = new AccessControlContext (result);
  205. state.setInGetContext(false);
  206. return context;
  207. }
  208. /**
  209. * Returns a snapshot of the current call stack as a two-element
  210. * array. The first element is an array of classes in the call
  211. * stack, and the second element is a boolean value indicating
  212. * whether the trace stopped early because a call to doPrivileged
  213. * was encountered. If this boolean value is true then the call to
  214. * doPrivileged will be the second-last frame in the returned trace.
  215. *
  216. * @return A snapshot of the current call stack.
  217. */
  218. private static native Object[] getStack();
  219. }