changeset 5126:ab7f904525f4

Initial push of prototype changes to extend access control
author alanb
date Fri, 30 Aug 2013 16:15:31 +0100
parents acac3bde66b2
children f919f164ef4f
files make/bsd/makefiles/mapfile-vers-debug make/bsd/makefiles/mapfile-vers-product make/linux/makefiles/mapfile-vers-debug make/linux/makefiles/mapfile-vers-product make/solaris/makefiles/mapfile-vers src/share/vm/classfile/classLoaderExports.cpp src/share/vm/classfile/classLoaderExports.hpp src/share/vm/classfile/javaClasses.cpp src/share/vm/classfile/javaClasses.hpp src/share/vm/classfile/vmSymbols.hpp src/share/vm/prims/jvm.cpp src/share/vm/prims/jvm.h src/share/vm/runtime/globals.hpp src/share/vm/runtime/mutexLocker.cpp src/share/vm/runtime/mutexLocker.hpp src/share/vm/runtime/reflection.cpp
diffstat 16 files changed, 451 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/make/bsd/makefiles/mapfile-vers-debug	Fri Aug 23 03:01:16 2013 -0700
+++ b/make/bsd/makefiles/mapfile-vers-debug	Fri Aug 30 16:15:31 2013 +0100
@@ -220,6 +220,7 @@
                 _JVM_SetClassSigners
                 _JVM_SetLength
                 _JVM_SetNativeThreadName
+                _JVM_SetPackageAccess
                 _JVM_SetPrimitiveArrayElement
                 _JVM_SetSockOpt
                 _JVM_SetThreadPriority
--- a/make/bsd/makefiles/mapfile-vers-product	Fri Aug 23 03:01:16 2013 -0700
+++ b/make/bsd/makefiles/mapfile-vers-product	Fri Aug 30 16:15:31 2013 +0100
@@ -220,6 +220,7 @@
                 _JVM_SetClassSigners
                 _JVM_SetLength
                 _JVM_SetNativeThreadName
+                _JVM_SetPackageAccess
                 _JVM_SetPrimitiveArrayElement
                 _JVM_SetSockOpt
                 _JVM_SetThreadPriority
--- a/make/linux/makefiles/mapfile-vers-debug	Fri Aug 23 03:01:16 2013 -0700
+++ b/make/linux/makefiles/mapfile-vers-debug	Fri Aug 30 16:15:31 2013 +0100
@@ -222,6 +222,7 @@
                 JVM_SetClassSigners;
                 JVM_SetLength;
                 JVM_SetNativeThreadName;
+                JVM_SetPackageAccess;
                 JVM_SetPrimitiveArrayElement;
                 JVM_SetSockOpt;
                 JVM_SetThreadPriority;
--- a/make/linux/makefiles/mapfile-vers-product	Fri Aug 23 03:01:16 2013 -0700
+++ b/make/linux/makefiles/mapfile-vers-product	Fri Aug 30 16:15:31 2013 +0100
@@ -222,6 +222,7 @@
                 JVM_SetClassSigners;
                 JVM_SetLength;
                 JVM_SetNativeThreadName;
+                JVM_SetPackageAccess;
                 JVM_SetPrimitiveArrayElement;
                 JVM_SetSockOpt;
                 JVM_SetThreadPriority;
--- a/make/solaris/makefiles/mapfile-vers	Fri Aug 23 03:01:16 2013 -0700
+++ b/make/solaris/makefiles/mapfile-vers	Fri Aug 30 16:15:31 2013 +0100
@@ -222,6 +222,7 @@
                 JVM_SetClassSigners;
                 JVM_SetLength;
                 JVM_SetNativeThreadName;
+                JVM_SetPackageAccess;
                 JVM_SetPrimitiveArrayElement;
                 JVM_SetSockOpt;
                 JVM_SetThreadPriority;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/classfile/classLoaderExports.cpp	Fri Aug 30 16:15:31 2013 +0100
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2013, 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.
+ *
+ * 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.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "classfile/classLoaderExports.hpp"
+#include "classfile/javaClasses.hpp"
+#include "oops/oop.inline.hpp"
+#include "runtime/handles.inline.hpp"
+#include "runtime/mutexLocker.hpp"
+
+ClassLoaderExports* ClassLoaderExports::_the_null_class_loader_exports = NULL;
+int ClassLoaderExports::_next_loader_tag = 0;
+
+// Returns the unique tag for the given loader, generating it if required
+int ClassLoaderExports::tag_for(Handle loader) {
+  // null loader
+  if (loader.is_null())
+     return 0;
+
+  jint tag = java_lang_ClassLoader::loader_tag(loader());
+  if (tag != 0)
+    return tag;
+
+  {
+    MutexLocker ml(LoaderTag_lock);
+    tag = ++_next_loader_tag;
+  }
+
+  jint* tag_addr = java_lang_ClassLoader::loader_tag_addr(loader());
+  jint prev = Atomic::cmpxchg(tag, tag_addr, 0);
+  if (prev != 0)
+    tag = prev;
+  return tag;
+}
+
+// returns the ClassLoaderExports for the given loader or null if none
+ClassLoaderExports* ClassLoaderExports::exports_for_or_null(Handle loader) {
+  if (loader.is_null()) {
+    return _the_null_class_loader_exports;
+  } else {
+    return java_lang_ClassLoader::exports_data(loader());
+  }
+}
+
+// returns the ClassLoaderExports for the given loader, creating if if needed
+ClassLoaderExports* ClassLoaderExports::exports_for(Handle loader) {
+  if (loader.is_null()) {
+    if (_the_null_class_loader_exports == NULL)
+      _the_null_class_loader_exports = new ClassLoaderExports(_exports_table_size);
+    return _the_null_class_loader_exports;
+  }
+
+  ClassLoaderExports** exports_addr = java_lang_ClassLoader::exports_data_addr(loader());
+  ClassLoaderExports* exports = new ClassLoaderExports(_exports_table_size);
+  ClassLoaderExports* prev = (ClassLoaderExports*) Atomic::cmpxchg_ptr(exports, exports_addr, NULL);
+  if (prev != NULL) {
+    delete exports;
+    exports = prev;
+  }
+  return exports;
+}
+
+// Set access control so that types defined by loader/pkg are accessible
+// only to the given runtime packages. Returns false if access control
+// is already set for the loader/package.
+bool ClassLoaderExports::set_package_access(Handle loader, const char* pkg,
+                                            objArrayHandle loaders, const char** pkgs)
+{
+  ClassLoaderExports* exports = exports_for(loader);
+
+  unsigned int hash = compute_hash(pkg);
+  int index = exports->hash_to_index(hash);
+
+  ClassLoaderExportEntry* first = exports->first_at(index);
+  ClassLoaderExportEntry* entry = first;
+  while (entry != NULL) {
+    if (entry->hash() == hash && strcmp(entry->package(), pkg) == 0) {
+        // already set, error for now
+        return false;
+    }
+    entry = entry->next();
+  }
+
+  entry = new ClassLoaderExportEntry(hash, pkg);
+  for (int i = 0; i < loaders->length(); i++) {
+    hash = compute_hash(pkgs[i]);
+    entry->add_allow(tag_for(loaders->obj_at(i)), pkgs[i], hash);
+  }
+
+  entry->set_next(first);
+  exports->set_first(index, entry);
+
+  return true;
+}
+
+// Verify that current_class can access new_class.
+bool ClassLoaderExports::verify_package_access(Klass* current_class, Klass* new_class) {
+  ClassLoaderExports* exports = exports_for_or_null(new_class->class_loader());
+  if (exports == NULL)
+    return true;
+
+  // ## FIXME encoding the external name is expensive in this prototype
+  ResourceMark rm;
+  char* name = (char*) new_class->external_name();
+  char* last = strrchr(name, '.');
+  if (last == NULL) {
+    // assume can't set access on the unnamed package for now
+    return true;
+  }
+  *last = '\0';
+  const char* pkg = name;
+
+  // package access setup for the package?
+  ClassLoaderExportEntry* entry = exports->find_entry(pkg);
+  if (entry == NULL) {
+    if (TracePackageAccess) {
+      tty->print_cr("%s -> %s access allowed (package not restricted)",
+        current_class->external_name(), pkg);
+    }
+    return true;
+  }
+
+  name = (char*) current_class->external_name();
+  last = strrchr(name, '.');
+  if (last == NULL) {
+    // assume can't set from unnamed package for now
+    if (TracePackageAccess) {
+        tty->print_cr("%s -> %s illegal access", current_class->external_name(),
+          new_class->external_name());
+    }
+    return false;
+  }
+  *last = '\0';
+  pkg = name;
+
+  // check access list to see if access from current_class is allowed
+  int tag = tag_for(current_class->class_loader());
+  unsigned int hash = compute_hash(pkg);
+  bool allowed = entry->can_access(tag, pkg, hash);
+  if (TracePackageAccess) {
+    tty->print("%s -> %s", current_class->external_name(), new_class->external_name());
+    if (allowed) {
+      tty->print_cr(" access allowed");
+    } else {
+      tty->print_cr(" illegal access");
+    }
+    tty->flush();
+  }
+  return allowed;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/vm/classfile/classLoaderExports.hpp	Fri Aug 30 16:15:31 2013 +0100
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2013, 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.
+ *
+ * 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.
+ *
+ */
+
+#ifndef SHARE_VM_CLASSFILE_CLASSLOADEREXPORTS_HPP
+#define SHARE_VM_CLASSFILE_CLASSLOADEREXPORTS_HPP
+
+#include "memory/allocation.hpp"
+#include "memory/allocation.inline.hpp"
+#include "runtime/handles.hpp"
+
+// Experimental support for access control. Many limitations in this
+// version (including performance, locking, class laoder unloading).
+
+// An entry in a list of loaders/packages that are allowed access
+
+class ClassLoaderAllowEntry : public CHeapObj<mtInternal> {
+ private:
+  int _loader_tag;
+  char* _pkg;
+  unsigned int _hash;
+  ClassLoaderAllowEntry* _next;
+ public:
+  ClassLoaderAllowEntry(int loader_tag, const char* pkg, int hash) {
+    _loader_tag = loader_tag;
+    _pkg = strdup(pkg);
+    _hash = hash;
+    _next = NULL;
+  }
+  int loader_tag()                             { return _loader_tag; }
+  const char* package()                        { return _pkg; }
+  unsigned int hash()                          { return _hash; }
+
+  ClassLoaderAllowEntry* next()               { return _next; }
+  void set_next(ClassLoaderAllowEntry* entry) { _next = entry; }
+};
+
+// Represents the export of package to a list of loaders/packages that are
+// allowed access.
+
+class ClassLoaderExportEntry : public CHeapObj<mtInternal> {
+ private:
+  unsigned int _hash;
+  char* _pkg;
+  ClassLoaderAllowEntry* _allows;
+  ClassLoaderExportEntry* _next;
+ public:
+  ClassLoaderExportEntry(unsigned int h, const char* p) {
+    _hash = h;
+    _pkg = strdup(p);
+    _allows = NULL;
+    _next = NULL;
+  }
+  unsigned int hash()       { return _hash; }
+  const char* package()     { return _pkg; }
+
+  ClassLoaderExportEntry* next()              { return _next; }
+  void set_next(ClassLoaderExportEntry* next) { _next = next; }
+
+  void add_allow(int loader_tag, const char* pkg, int hash) {
+    ClassLoaderAllowEntry* entry = new ClassLoaderAllowEntry(loader_tag, pkg, hash);
+    entry->set_next(_allows);
+    _allows = entry;
+  }
+
+  bool can_access(int loader_tag, const char* pkg, unsigned int hash) {
+    ClassLoaderAllowEntry* entry = _allows;
+    while (entry != NULL) {
+      if (hash == entry->hash() && loader_tag == entry->loader_tag() &&
+         (strcmp(pkg, entry->package()) == 0))
+        return true;
+      entry = entry->next();
+    }
+    return false;
+  }
+};
+
+
+// There is a ClassLoaderExports per class loader that has enabled package access.
+// ClassLoaderExports are "kept alive" via an injected field in ClassLoader. To
+// avoid refernces between loaders then each loader is given a unique tag,
+// generated when its ClassLoaderExports is created.
+
+class ClassLoaderExports : public CHeapObj<mtInternal> {
+ private:
+  enum Constants {
+    _exports_table_size = 107
+  };
+
+  // special for the null loader
+  static ClassLoaderExports * _the_null_class_loader_exports;
+
+  // used to compute the per-loader tag
+  static int _next_loader_tag;
+
+  // returns the unique tag for the given loader, creating if if needed
+  static jint tag_for(Handle loader);
+
+  // returns the ClassLoaderExports for the given loader or null if none
+  static ClassLoaderExports* exports_for_or_null(Handle loader);
+
+  // returns the ClassLoaderExports for the given loader, creating if if needed
+  static ClassLoaderExports* exports_for(Handle loader);
+
+  // compute the hash code for the given package name
+  static unsigned int compute_hash(const char* pkg) {
+    unsigned int hash = 0;
+    int len = (int)strlen(pkg);
+    while (len-- > 0) {
+      hash = 31*hash + (unsigned) *pkg;
+      pkg++;
+    }
+    return hash;
+  }
+
+  // hash table and size
+  // ## change this class to use Hashtable template
+  ClassLoaderExportEntry** _table;
+  int _table_size;
+
+  // create with a hash table of the given size
+  ClassLoaderExports(int table_size) {
+    _table_size = table_size;
+    _table = (ClassLoaderExportEntry**) NEW_C_HEAP_ARRAY(ClassLoaderExportEntry*, _table_size, mtInternal);
+    for (int i = 0; i < _table_size; i++) {
+      _table[i] = NULL;
+    }
+  }
+
+  // simple mapping of hash to entry in hash table
+  int hash_to_index(unsigned int hash) {
+    return hash % _table_size;
+  }
+
+  // return the first entry at the given index
+  ClassLoaderExportEntry* first_at(int index) {
+    assert(index >= 0 && index < _table_size, "index out of range");
+    return _table[index];
+  }
+
+  // set the first entry at the given index
+  void set_first(int index, ClassLoaderExportEntry* entry) {
+    assert(index >= 0 && index < _table_size, "index out of range");
+    _table[index] = entry;
+  }
+
+  // search the table for the given package, returns NULL if not found
+  ClassLoaderExportEntry* find_entry(const char* pkg) {
+    unsigned int hash = compute_hash(pkg);
+    int index = hash_to_index(hash);
+    assert(index >= 0 && index < _table_size, "index out of range");
+
+    ClassLoaderExportEntry* entry = _table[index];
+    while (entry != NULL) {
+      if (entry->hash() == hash && strcmp(entry->package(), pkg) == 0) {
+        break;
+      }
+      entry = entry->next();
+    }
+    return entry;
+  }
+
+ public:
+
+  // Set access control so that types defined by loader/pkg are accessible
+  // only to the given runtime packages. Returns false if access control
+  // is already set for the loader/package.
+  static bool set_package_access(Handle loader, const char* pkg,
+                                 objArrayHandle loaders, const char** pkgs);
+
+  // Verify that current_class can access new_class.
+  static bool verify_package_access(Klass* current_class, Klass* new_class);
+};
+
+#endif // SHARE_VM_CLASSFILE_CLASSLOADEREXPORTS_HPP
--- a/src/share/vm/classfile/javaClasses.cpp	Fri Aug 23 03:01:16 2013 -0700
+++ b/src/share/vm/classfile/javaClasses.cpp	Fri Aug 30 16:15:31 2013 +0100
@@ -2902,6 +2902,8 @@
 
 bool java_lang_ClassLoader::offsets_computed = false;
 int  java_lang_ClassLoader::_loader_data_offset = -1;
+int  java_lang_ClassLoader::_loader_tag_offset = -1;
+int  java_lang_ClassLoader::_exports_data_offset = -1;
 int  java_lang_ClassLoader::parallelCapable_offset = -1;
 
 ClassLoaderData** java_lang_ClassLoader::loader_data_addr(oop loader) {
@@ -2913,6 +2915,24 @@
   return *java_lang_ClassLoader::loader_data_addr(loader);
 }
 
+jint* java_lang_ClassLoader::loader_tag_addr(oop loader) {
+  assert(loader != NULL && loader->is_oop(), "loader must be oop");
+  return (jint*) loader->address_field_addr(_loader_tag_offset);
+}
+
+jint java_lang_ClassLoader::loader_tag(oop loader) {
+  return *java_lang_ClassLoader::loader_tag_addr(loader);
+}
+
+ClassLoaderExports** java_lang_ClassLoader::exports_data_addr(oop loader) {
+  assert(loader != NULL && loader->is_oop(), "loader must be oop");
+  return (ClassLoaderExports**) loader->address_field_addr(_exports_data_offset);
+}
+
+ClassLoaderExports* java_lang_ClassLoader::exports_data(oop loader) {
+  return *java_lang_ClassLoader::exports_data_addr(loader);
+}
+
 void java_lang_ClassLoader::compute_offsets() {
   assert(!offsets_computed, "offsets should be initialized only once");
   offsets_computed = true;
--- a/src/share/vm/classfile/javaClasses.hpp	Fri Aug 23 03:01:16 2013 -0700
+++ b/src/share/vm/classfile/javaClasses.hpp	Fri Aug 30 16:15:31 2013 +0100
@@ -1209,7 +1209,11 @@
 // Interface to java.lang.ClassLoader objects
 
 #define CLASSLOADER_INJECTED_FIELDS(macro)                            \
-  macro(java_lang_ClassLoader, loader_data,  intptr_signature, false)
+  macro(java_lang_ClassLoader, loader_data,  intptr_signature, false) \
+  macro(java_lang_ClassLoader, loader_tag,   int_signature,    false) \
+  macro(java_lang_ClassLoader, exports_data, intptr_signature, false)
+
+class ClassLoaderExports;
 
 class java_lang_ClassLoader : AllStatic {
  private:
@@ -1218,6 +1222,8 @@
    hc_parent_offset = 0
   };
   static int _loader_data_offset;
+  static int _loader_tag_offset;
+  static int _exports_data_offset;
   static bool offsets_computed;
   static int parent_offset;
   static int parallelCapable_offset;
@@ -1228,6 +1234,12 @@
   static ClassLoaderData** loader_data_addr(oop loader);
   static ClassLoaderData* loader_data(oop loader);
 
+  static jint* loader_tag_addr(oop loader);
+  static jint loader_tag(oop loader);
+
+  static ClassLoaderExports** exports_data_addr(oop loader);
+  static ClassLoaderExports* exports_data(oop loader);
+
   static oop parent(oop loader);
   static bool isAncestor(oop loader, oop cl);
 
--- a/src/share/vm/classfile/vmSymbols.hpp	Fri Aug 23 03:01:16 2013 -0700
+++ b/src/share/vm/classfile/vmSymbols.hpp	Fri Aug 30 16:15:31 2013 +0100
@@ -395,6 +395,8 @@
   template(init_lock_name,                            "init_lock")                                \
   template(signers_name,                              "signers_name")                             \
   template(loader_data_name,                          "loader_data")                              \
+  template(loader_tag_name,                           "loader_tag")                               \
+  template(exports_data_name,                         "exports_data")                             \
   template(dependencies_name,                         "dependencies")                             \
                                                                                                   \
   /* non-intrinsic name/signature pairs: */                                                       \
--- a/src/share/vm/prims/jvm.cpp	Fri Aug 23 03:01:16 2013 -0700
+++ b/src/share/vm/prims/jvm.cpp	Fri Aug 30 16:15:31 2013 +0100
@@ -24,6 +24,7 @@
 
 #include "precompiled.hpp"
 #include "classfile/classLoader.hpp"
+#include "classfile/classLoaderExports.hpp"
 #include "classfile/javaAssertions.hpp"
 #include "classfile/javaClasses.hpp"
 #include "classfile/symbolTable.hpp"
@@ -975,6 +976,31 @@
             (jclass) JNIHandles::make_local(env, k->java_mirror());
 JVM_END
 
+JVM_ENTRY(void, JVM_SetPackageAccess(JNIEnv *env, jobject loader, jstring pkg,
+                                     jobjectArray loaders, jobjectArray pkgs))
+  JVMWrapper("JVM_SetPackageAccess");
+  ResourceMark rm(THREAD);
+
+  Handle loader_h(THREAD, JNIHandles::resolve(loader));
+  objArrayHandle loaders_h(THREAD, objArrayOop(JNIHandles::resolve_non_null(loaders)));
+
+  const char* pkg_str = java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(pkg));
+
+  objArrayOop pkgs_array = objArrayOop(JNIHandles::resolve_non_null(pkgs));
+  assert(loaders_h->length() == pkgs_array->length(), "length should be the same");
+
+  char** pkgs_str_array = NEW_RESOURCE_ARRAY(char*, pkgs_array->length());
+  for (int i = 0; i < pkgs_array->length(); i++) {
+    pkgs_str_array[i] = java_lang_String::as_utf8_string(pkgs_array->obj_at(i));
+  }
+
+  if (!ClassLoaderExports::set_package_access(loader_h, pkg_str, loaders_h, (const char**) pkgs_str_array)) {
+    // ## FIXME: Changing the exports after they have been set needs discussion
+    THROW_MSG(vmSymbols::java_lang_IllegalStateException(), "package access already set");
+  }
+
+JVM_END
+
 
 // Reflection support //////////////////////////////////////////////////////////////////////////////
 
--- a/src/share/vm/prims/jvm.h	Fri Aug 23 03:01:16 2013 -0700
+++ b/src/share/vm/prims/jvm.h	Fri Aug 30 16:15:31 2013 +0100
@@ -446,6 +446,10 @@
                               jsize len, jobject pd, const char *source,
                               jboolean verify);
 
+JNIEXPORT void JNICALL
+JVM_SetPackageAccess(JNIEnv *env, jobject loader, jstring pkg,
+                     jobjectArray loaders, jobjectArray pkgs);
+
 /*
  * Reflection support functions
  */
--- a/src/share/vm/runtime/globals.hpp	Fri Aug 23 03:01:16 2013 -0700
+++ b/src/share/vm/runtime/globals.hpp	Fri Aug 30 16:15:31 2013 +0100
@@ -1299,6 +1299,10 @@
   product(bool, TraceClassResolution, false,                                \
           "Trace all constant pool resolutions (for debugging)")            \
                                                                             \
+  develop(bool, TracePackageAccess, false,                                  \
+          "Trace access control when set to only allow access from types"   \
+          "in configured runtime packages")                                 \
+                                                                            \
   product(bool, TraceBiasedLocking, false,                                  \
           "Trace biased locking in JVM")                                    \
                                                                             \
--- a/src/share/vm/runtime/mutexLocker.cpp	Fri Aug 23 03:01:16 2013 -0700
+++ b/src/share/vm/runtime/mutexLocker.cpp	Fri Aug 30 16:15:31 2013 +0100
@@ -132,6 +132,8 @@
 Mutex*   JfrStream_lock               = NULL;
 Monitor* PeriodicTask_lock            = NULL;
 
+Mutex*   LoaderTag_lock               = NULL;
+
 #define MAX_NUM_MUTEX 128
 static Monitor * _mutex_array[MAX_NUM_MUTEX];
 static int _num_mutex;
@@ -277,6 +279,8 @@
   def(JfrBuffer_lock               , Mutex,   nonleaf+1,   true);
   def(JfrStream_lock               , Mutex,   nonleaf+2,   true);
   def(PeriodicTask_lock            , Monitor, nonleaf+5,   true);
+
+  def(LoaderTag_lock               , Mutex,   leaf,        true);
 }
 
 GCMutexLocker::GCMutexLocker(Monitor * mutex) {
--- a/src/share/vm/runtime/mutexLocker.hpp	Fri Aug 23 03:01:16 2013 -0700
+++ b/src/share/vm/runtime/mutexLocker.hpp	Fri Aug 30 16:15:31 2013 +0100
@@ -145,6 +145,8 @@
 extern Mutex*   JfrStream_lock;                  // protects JFR stream access
 extern Monitor* PeriodicTask_lock;               // protects the periodic task structure
 
+extern Mutex*   LoaderTag_lock;                  // used to generate a unique loader tag (experimental)
+
 // A MutexLocker provides mutual exclusion with respect to a given mutex
 // for the scope which contains the locker.  The lock is an OS lock, not
 // an object lock, and the two do not interoperate.  Do not use Mutex-based
--- a/src/share/vm/runtime/reflection.cpp	Fri Aug 23 03:01:16 2013 -0700
+++ b/src/share/vm/runtime/reflection.cpp	Fri Aug 30 16:15:31 2013 +0100
@@ -23,6 +23,7 @@
  */
 
 #include "precompiled.hpp"
+#include "classfile/classLoaderExports.hpp"
 #include "classfile/javaClasses.hpp"
 #include "classfile/symbolTable.hpp"
 #include "classfile/systemDictionary.hpp"
@@ -458,10 +459,13 @@
   // doesn't have a classloader.
   if ((current_class == NULL) ||
       (current_class == new_class) ||
-      (new_class->is_public()) ||
       is_same_class_package(current_class, new_class)) {
     return true;
   }
+  if (new_class->is_public()) {
+    return ClassLoaderExports::verify_package_access(current_class, new_class);
+  }
+
   // New (1.4) reflection implementation. Allow all accesses from
   // sun/reflect/MagicAccessorImpl subclasses to succeed trivially.
   if (   JDK_Version::is_gte_jdk14x_version()