JDK-4302406 : Package sealing and creation of java.lang.Package objects is inconsistent.
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.lang
  • Affected Version: 1.4.0
  • Priority: P4
  • Status: Closed
  • Resolution: Other
  • OS: generic
  • CPU: generic
  • Submitted: 2000-01-04
  • Updated: 2017-12-20
  • Resolved: 2016-03-23
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 9
9Resolved
Related Reports
Relates :  
Relates :  
Description
----------------------------------------------------------------------

Please note that the file which is attached to this report, 
kestrel-issues-summary.txt, contains a discussion of issues that are 
related to Merlin functionality which is known as "Preferred Classes."  
This file was mailed to jdk-extmech@eng.  This discussion provides 
useful and important background information for this bug.

----------------------------------------------------------------------

Package sealing does not enforce restrictions on child class loaders
consistently.  Parent and child class loaders can contain duplicate 
java.lang.Package definitions which are both sealed:

As it currently interacts with the class loader delegation model,
sealing a package now has the following effect: If a JAR file seals a
package, foo, and that JAR file is a resource of a URLClassLoader, and
at least one class, foo.Bar, in that package can only be found in that
class loader (i.e. not by delegating to a parent) from that JAR file,
then sealing enforces the following restriction: If any class in that
package has been defined by an ancestor class loader (i.e. the
ancestor called definePackage for "foo"), then an exception will be
thrown when the URLClassLoader attempts to define foo.Bar from its JAR
(assuming the JAR has a different seal base than the parent's
package).  In other words, a child class loader cannot create a new
sealed package if it or a parent class loader has already defined an
equivalent package (sealed or not).  Additionally, a URLClassLoader
will also throw a "sealing violation" exception if it is asked to
define a class in a package to a different seal base than that of an
equivalent package that any of its ancestors may have sealed.  Sealing
is intended to enable parent class loaders to prevent the creation of any 
duplicate packages in child class loaders, but since 

The important point to take from the above description is that a Java
package is not sealed until a Package object has been created for it
(this will happen when some class loader first calls defineClass(...)
for a class which declares itself as a member of a relevant
package).  If a child class loader creates a Package before a parent
has a chance to seal or create that Package, the child will be able to
create a sealed Package that a parent class loader might load 
(possibly sealed) later on.  That fact that this situation can occur
goes against the original design of Package sealing.  Specifically, 
it is possible for a child class loader and a parent class loader to
both create duplicate Package objects which describe the same Java
package (this is true as long as the child class loader creates its 
Package object before any parent has a chance to do so).  This behavior
invalidates that claim that if a package is sealed with respect to one
sealbase, then all classes in that package must be loaded from that 
sealBase.

One particularly useful aspect of package sealing is that it can be
used to force a child class loader to make a choice to use all of its
own or all of its parents resources in a given package but not a
combination of both.  However, as described above, class loading order
dependencies make it difficult to know exactly when a sealing
violation will be thrown when a class loader attempts to create a
Package.  Because of this, package sealing can not always be used to
guarantee package version consistency among the classes in a "single" 
package.  The current implementation of sealing should be changed to 
fully support loading restrictions that a parent wishes to enforce
for all its child class loaders.


Also see the attached files for package-test.tar for a simple test 
which demonstrates inconsistencies described in this report.






Comments
Package API has been updated in jdk-9+111 and this issue has been resolved. See the summary of the API change described at: https://bugs.openjdk.java.net/browse/JDK-8061804?focusedCommentId=13916978&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-13916978 The sealing violation is checked against the Package object defined by this class loader. Package objects defined by its ancestor class loader is irrelevant to the sealing violation check in JDK 9. Packages in named modules are implicitly sealed. A class loader cannot have a duplicated package defined from multiple modules.
23-03-2016

SUGGESTED FIX The attached kestrel-summary document defines the following effects of Java package sealing in detail: Downward sealing and Upward sealing. The attached document finds that consistent Downward sealing was intended to implement licensing restrictions such as "Namespace sealing" and that upward sealing is useful to applications to allow them to ensure package level version consistency. The docuemnt also describes the general inconsistent behavior of package sealing as making the tool much less useful than it was originally though it would be. Since the kestrel-summaries document was written, the RMI team has learned more information pertaining to consistent implementation of downward and upward sealing: ---------- A. Downward sealing - allows a parent class loader to prevent a child from a defining a class in a package if the parent has already define a sealed Package object for that Java package. In order to implement downward sealing without loading order dependencies (discussed in the description of this report), when a child class loader loads a class in a given package, the child needs to know if a parent class loader will at some time in the future, attempt to define a sealed Package object for the Java package from which the child needs to load classes. In order to answer queries of this form, whenever a parent class loader receives a delegation from a child to load a class, the parent must search its resources (assuming the parent does not have a copy of the requested class) to determine if it might ever define a class in the same package as the class the child wishes to load. If a child class loader knew if a parent was going to use a duplicate sealed package of a package the child was attempting to define, the child could simply throw sealing violations when the potential duplicate was detected and downward sealing would be preserved. But it appears that the search space that a parent class loader would have to scan to gain this information is quite large; for a parent to determine if it had any class in a sealed package in a JAR file, the parent would have to open all of its JARs to look at their package and sealing information and compare them to the package of the class the child wished to load - this search would be expensive but possible. However, a parent class loader would also have to scan "directory" urls for classes that did not reside in JAR files to see if it would load them in place of classes that might reside in the parent's JAR resources. If the parent were to load the class from a directory instead of a sealed package in a JAR the parent would not seal the relevant package. For a class loader to know if it would load classes from a directory (given only a package name a search criteria), the class loader would have to scan all *possible* class names above the directory being searched. Since it is not feasible for class loaders to perform this type of search, parent class loader's can not tell children if they would ever attempt to define sealed Packages which would be duplicates of child Packages. As a result, it appears impossible to implement downward sealing consistently. When defining a Package, child class loaders are currently forced to ignore the possibility that a parent class loader might create a sealed Package object which would be a duplicate of a Package that a child wishes to create. This behavior leads leads to the inconsistencies described in this report. ---------- B. Upward sealing - enables a child class loader to ensure that it will use "all or none" of its parents resources. Upward sealing enables a child class loader to ensure version consistency among all the classes defined in a single package. Like downward sealing, upward sealing also has inconsistencies which arise as a result of load order dependencies. If a child class loader defines a class in a sealed package, and later, it delegates to a parent to load a class in the same package, if the parent has the relevant class, the parent will associate the class with its own duplicat Package object. Even though the child intended that all classes come from its own resources it would end up using a class defined in a parent's package anyway. We believe that it would be more desirable for the child to have thrown a sealing violation when it saw that a) it had already loaded a class in it's own sealed package and b) the delegation model mandated that the class loader use a parent's version of a class in place of its own version. Even though the child class loader would not detect that it was asked to use a mix of its own and its parent's classes until after it had defined some of its own classes, package version consistency is guaranteed. In other words, the child class loader would successfully be able to define classes in its own sealed package, and fail later on when it saw that it was about to use classes from a parent. This is not the most desirable situation but at least it does preserve the "all or none" semantics we feel upward sealing should preserve. We believe that detecting the failure earlier, would require the same type of "large namespace" query that downward sealing requires. To implement upward sealing, a child class loader should behave (more or less...) as follows when requested to load a class: // maps of packages that parent and child class loaders have defined HashMap parentDefined; HashMap childDefinedSealed; Class loadClass(String name) throws ClassNotFoundException { String packageOf = packageOf(name); // detect sealing violations from caches if ((parentDefined.get(packageOf) != null) && (childDefinedSealed.get(packageOf) != null)) { throw new SealingViolation("attempt to mix parent and sealed child classes"); } Class cl = parent.loadClass(name); if (cl != null) { // parent has defined the package of name parentDefined.put(packageOf, packageOf); } if ((parentDefined.get(packageOf) != null) && (childDefinedSealed.get(packageOf) != null)) { throw new SealingViolation("attempt to mix parent and sealed child classes"); } if (cl == null) { cl = findClass(name); if (cl != null) { if (cl.getPackage().isSealed()) { childDefinedSealed.put(packageOf, packageOf); if (parentDefined.get(packageOf) != null) { throw new SealingViolation("attempt to mix parent " + "and sealed child classes"); } } } else { throw ClassNotFoundException("..."); } } return cl; } The child class loader tracks what classes it loads and what sealed classes its parent loads. The child class loader is responsible for knowing when a class found by a delegation to a parent should be discarded in order to avoid an undetected upward sealing violation. ---------- As a result of the above implementation restrictions and other details (which are discussed in the Kestrel summaries document) the RMI team has come to the following conclusions: 1) Downward sealing is a) *difficult*/impossible to implement consistently b) not useful as a Namespace restriction mechanism c) not needed to protect the "java." namespace (which is what is most important) d) not needed to implement class loading security guarantees 2) Upward sealing a) can be implemented b) is useful to ensure package level version consistency The RMI team reccommends that upward sealing be fixed using the approach described above and that the documentation for sealing be changed to either describe the inherent load order dependencies in downward sealing or changed to mention that package sealing should not be used for downward sealing at all.
11-06-2004