| <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN2"> |
| <html> |
| <head> |
| <title>Strict Classloading</title> |
| <meta http-equiv="Content-Type" content="text/html; charset=utf-8"> |
| <meta http-equiv="Content-Style-Type" content="text/css"> |
| <link href="http://dev.eclipse.org/default_style.css" rel="stylesheet" type="text/css"> |
| </head> |
| <body bgcolor="#ffffff"> |
| |
| <table width="100%"> |
| <tr><td style="background:#0080C0"><b><span style="color:white">Proposal</span></b></td></tr> |
| </table> |
| <h1>Strict Classloading</h1> |
| <blockquote> |
| <p><b>Summary</b> <br> |
| Eclipse embodies a component/modularity model. It allows plug-ins to express |
| what they need of others (requiring plug-ins and importing packages) as well |
| as what they contribute to others (providing/exporting packages). Ideally |
| plug-ins would export/provide only that code which they consider to be API. |
| Historically however the Eclipse plug-ins (and likely much of the community) |
| have exported all of the code they contain. This is helpful to consumers |
| living on the edge or pushing the envelope but it hinders both security as |
| well as static API analysis done for security or performance optimization. |
| Here we propose a path forward which allows plug-in producers to express their |
| API and thus the runtime to enforce API-only consumption but still enables |
| wild-men developers to access non-API on a selective basis. |
| <p>Last |
| Modified: December 16, 2004</p> |
| </blockquote> |
| |
| <h2>Problem Definition</h2> |
| <p>Currently the Eclipse plug-ins expose all their code. The typical plugin.xml looks |
| something like</p> |
| <pre> <plugin ...> |
| <runtime><br> <library name="resources.jar"><br><strong><font color="#FF0000"> <export name="*"/><br></font></strong> </library><br> </runtime> |
| </plugin></pre> |
| <p>The use of * in the export filter means that all classes in the related |
| JAR are exposed to consumers. Typically these JARs contain both API and implementation |
| classes.</p> |
| <p>Beyond the appalling aesthetics of exposing the non-API classes, there are a |
| number of pragmatic reasons why this is bad. In particular, this practice inhibits |
| runtime security and static analysis.</p> |
| <h3>Issue: Runtime Security</h3> |
| <p>Key to the Java security model is understanding and limiting the entry points |
| to a piece of function. The security mechanisms are costly both at execution |
| and development time. It is simply infeasible to secure every part of a large |
| chunk of code like Eclipse if we have to consider all visible methods on all |
| visible classes as entry points. Instead, we look to the API to provide a choke |
| point |
| through which all external access must go. If we secure the API then the implementation |
| code need not be secured (or at least requires less work to secure). Of course, |
| if you take this approach, the runtime must gurarantee that only the API types |
| are visible to outside parties. To do this, there must be a clear, machine-readable |
| description of these types in a plug-in.</p> |
| <h3>Issue: Static Analysis</h3> |
| <p>Static code analysis is increasingly interesting. It enables both security analysis |
| and verification as well as performance optimizations such as code reduction |
| and inlining. These analysis techniques begin by identifying the entry points |
| in a body of code and then exhaustively traversing all execution paths. In |
| the case of security analysis, the algorithm is looking for unsafe operations |
| and places where permissions are required. For performance analysis the tools |
| look for dead code (code which is not traversed), inlining opportunities and |
| classes, methods and fields which can be obfuscated. Without an explicit and |
| complete specification of the API, these analyses are not possible. </p> |
| <h3>Issue: Internal Type Access</h3> |
| <p>Historically Eclipse has not limited access to the internal classes of a plug-in. |
| We define the API in Javadoc and warn programmers not to stray. This approach |
| is weak and leads to component interaction via non-API routes. Enforcing API-only |
| visibility eliminates this weakness. </p> |
| <p>Despite the pitfalls, |
| some developers find it convenient or necessary to use internal classes. |
| Some Eclipse plug-ins have been known to do this! In addition, various test |
| suites |
| rely on access to internal types to implement white-box tests. Simply cutting |
| off this access is not friendly.</p> |
| <h3>Issue: Accurate Development-time Classpaths</h3> |
| <p>PDE builds development time classpaths from the exported packages it finds in |
| the plug-ins it manages. Because Eclipse plug-ins typically export all their |
| code, dependent plug-ins have all internal classes on their classpath at development |
| time. This can lead to unintended use of internals through the convenience |
| of code completion. Developers know there is a type called FooBar so type Foo<ctrl><space> |
| and choose from the results (or use Organize Imports). Because they find a |
| type and things seem to work they are happy. Unfortunately, it is entirely |
| possible that the FooBar used is not API since PDE has no way of telling the |
| difference.</p> |
| <h2>Proposal</h2> |
| <p>Plug-in producers are in the best position to define their API. They clearly know |
| the bounds of what they want to expose/support. Actually defining the |
| API is not particularly challenging. The plugin.xml <export name=""/> syntax |
| and manifest.mf Export-Package: header both allow export specification. The |
| specifications are given using an obvious and simple format. For example, the |
| plugin.xml and manifest.mf markup (only one is needed) to expose the API for |
| the Resource plug-in is shown below.</p> |
| <pre> <plugin ...> |
| <runtime><br> <library name="resources.jar"><br><strong><font color="#FF0000"> <export name="org.eclipse.core.resources, org.eclipse.core.resources.refresh, |
| org.eclipse.core.resources.team"/><br></font></strong> </library><br> </runtime> |
| </plugin></pre> |
| <pre> <strong><font color="#FF0000">Export-Package: |
| org.eclipse.core.resources, |
| org.eclipse.core.resources.refresh, |
| org.eclipse.core.resources.team</font></strong> |
| </pre> |
| <h3>Defining the Exports</h3> |
| <p>The task of defining the exports is relatively straightforward. For most plug-ins |
| it amounts to creating entries similar to those above. Notice that packages |
| which are not to be exposed are simply not listed. Since Eclipse already uses |
| package naming conventions for API packages, this process should take about |
| 5 minutes per Eclipse plug-in. Simply open the jar for a plug-in and note all |
| of the API packages. |
| List these packages in your choice of manifest (plugin.xml or manifest.mf). |
| The effort required for non-Eclipse plug-ins which may not follow any package |
| naming conventions may be slightly greater but is still quite minimal.</p> |
| <p>Note that classes used in executable extensions and Bundle.loadClass() do not |
| need to be listed in the exports as they are loaded by asking the plug-in itself |
| to |
| load |
| the class rather than going through the normal classloader delegation mechanism.</p> |
| <p>Of course, if you are using non-API in someone else's plug-in you will have to |
| either clean up your code or negotiate to have the required types exposed by |
| the prerequisite plug-in.</p> |
| <p>Notice also that there is a subtle difference between exposing a type and it |
| being API. A type is not API simply because it is exported by a plug-in's manifest. |
| plug-ins may be willing to expose types which are provisional API or specific |
| types which are made available for targetted users (e.g, so-called SPI). The |
| definition of API remains under this model. That is, the Javadoc is still the |
| final source.</p> |
| <h3>Exposing Internals (Strict mode)</h3> |
| <p><em>[Note: We need a better name here. "strict mode" is hard to negate (what is the |
| opposite?). "test mode" is ok but has a wider connotation. Strict mode may |
| in fact be one aspect of a supposed test mode but it likely does not cover |
| all aspects.]</em></p> |
| <p>As mentioned in the problem definition, various people expect access to a wider |
| range of classes. To support this we introduce a new (non-standard) OSGi manifest.mf |
| header <em>Export-InternalPackage</em> and a <em>osgi.strictClassLoading</em> property for the framework. The Export-InternalPackage header has exactly the |
| same syntax as Export-Package.</p> |
| <p>When the framework is in <em>strict mode</em> (i.e., |
| osgi.strictClassLoading = true), only types listed by the Export-Package headers |
| are considered. When |
| the framework is in <em>non-strict</em> mode (i.e., osgi.strictClassLoading |
| = false), the elements on the Export-Package and Export-InternalPackage headers |
| are merged (in that order) and considered by the runtime.</p> |
| <p>We do not propose any changes to the plugin.xml syntax. Developers using plugin.xml |
| can specify their exports as outlined above and the manifest generator will |
| automatically generate Export-InternalPackage header entries for all packages |
| found in the plug-in but not included in the generated Export-Package header. |
| Note however that the manifest.mf format offers additional power in filtering |
| types from a package. Developers wishing to be more precise about their exports |
| (sub-package control) can acheive this using the manifest.mf file.</p> |
| <p>By default Eclipse will default to non-strict mode (osgi.strictClassLoading = |
| false) so as to increase compatibility. </p> |
| <p>As a bare minimum the Eclipse RCP plug-ins must operate correctly in strict mode. |
| Optimally the entire Eclipse SDK will operate correctly in strict mode. </p> |
| <h3>Runtime/OSGi impact</h3> |
| <p>The OSGi code needs to support the strict mode flag. This impacts the following |
| areas:</p> |
| <ul> |
| <li><strong>Resolver:</strong> The code which gathers the list of exported packages |
| now has to optionally gather elements from the Export-InternalPackage header.</li> |
| <li><strong>State cache:</strong> The state cache change detection test needs to include a check that the strictness |
| flag is the same as this affects the package wirings. If the strictness changes, |
| the state cache needs to be flushed.</li> |
| </ul> |
| <h3>PDE UI impact</h3> |
| <p>PDE UI will need to expose the new export header in the appropriate way (e.g., |
| in the package related editor pages). There are several things to note here</p> |
| <ul> |
| <li>The Export-Package header allows includes/exclude filters to be |
| specified. These should be exposed</li> |
| <li>The ability to put a given package found in a bundle in either export list or |
| explicitly not export it at all should be supported.</li> |
| <li>PDE will likely have to retain a list of the packages and types |
| which have |
| been expressly NOT put on either the Export-Package or Export-InternalPackage |
| headers. These are elements which the developer has decided to keep private |
| in all cases. Maintaining this list is needed to differentiate between |
| elements are not mentioned in either header because they are new |
| or because they are to be private. The negative list can |
| be kept in a separate manifest header (favoured) or though separate metadata |
| (e.g., build.properties).</li> |
| </ul> |
| <p>PDE should offer the developer the option to use strict mode development-time |
| classpaths. The semantics are the same here as putting the runtime in strict |
| mode. That is, in strict mode only the Export-Package header is used where |
| as in non-strict mode all exports are used. There may be an additional/related |
| ability to add the Export-InternalPackage entries to the secondary classpath |
| for a plug-in project.</p> |
| <p>In any event, PDE should use the new JDT classpath includes/excludes capabilities |
| to match the compiler classpath to the actual runtime classpath as close as |
| possible.</p> |
| <h3>PDE Build impact</h3> |
| <p>PDE build likely needs some switches similar to those described above to manage |
| the classpath computations.</p> |
| <h3>Manifest generator impact</h3> |
| <p>As mentioned above, the manifest generator will be updated to generate Export-InternalPackage: |
| entries for every package /type that is not listed in the Export-Package header. </p> |
| <h3>Additional impacts</h3> |
| <p>All RCP plug-ins are expected to run correctly in strict mode. This means that |
| their Export-Package list must include all API as well as any packages/classes |
| which are known to be required by friendly plugins. Again, the Export-Package |
| list is NOT a declaration of API. It is a visibility statement much like the |
| public keyword in Java.</p> |
| <h3>Other notes</h3> |
| <p>The exact syntax of the package lists is open to change. The use of OSGi directives |
| on the standard Export-Package header (for example) has been suggested. The |
| various approaches have benefits and drawbacks and will be considered as an |
| implementation detail. Here we note that the final syntax may not be as |
| described above.</p> |
| <h2>Summary</h2> |
| <p>This proposal details the set of changes required to correctly and completely |
| specify the public face (including API) of a plug-in. These changes are needed |
| to allow Eclipse to run in a secure mode as well as facilitating various analysis |
| techniques for security and performance optimization. The changes are quite |
| modest and can be completed by related teams with limited effort.</p> |
| <p> </p> |
| <p> </p> |
| </body> |
| </html> |