DO NOT REPLY TO THIS EMAIL, BUT PLEASE POST YOUR BUG 
RELATED COMMENTS THROUGH THE WEB INTERFACE AVAILABLE AT
<http://issues.apache.org/bugzilla/show_bug.cgi?id=28256>.
ANY REPLY MADE TO THIS MESSAGE WILL NOT BE COLLECTED AND 
INSERTED IN THE BUG DATABASE.

http://issues.apache.org/bugzilla/show_bug.cgi?id=28256

WebappClassLoader.findClassInternal() permission problems

           Summary: WebappClassLoader.findClassInternal() permission
                    problems
           Product: Tomcat 5
           Version: 5.0.19
          Platform: Sun
        OS/Version: Solaris
            Status: NEW
          Severity: Blocker
          Priority: Other
         Component: Catalina
        AssignedTo: [EMAIL PROTECTED]
        ReportedBy: [EMAIL PROTECTED]
                CC: [EMAIL PROTECTED]


In summary, because WebappClassLoader extends the behavior of
URLClassLoader's findClass method, it needs to insulate its extended
behavior in a doPrivileged block (with a stored AccessControlContext)
just like URLClassLoader.findClass does.

The findClassInternal method of WebappClassLoader does not execute as a
privileged operation, but a brief glance the source to its superclass,
URLClassLoader, shows that it needs to.  A class loader needs to
insulate itself from the arbitrary security context in which it might
be invoked (such as during lazy class loading).

The specific problem we are encountering is a bit complex, but in
brief, the bug occurs when attempting to load a class using a class
loader whose parent is a servlet's WebappClassLoader-- the loading
fails with a security exception.  (This situation can come about when,
for example, a servlet attempts to download the proxy for a Jini
service, for which the service proxy's class gets loaded using the
RMIClassLoader.loadClass API.)

When the child class loader, which is also a URLClassLoader, defines a
class that it has loaded itself, that operation executes as a
privileged operation restricted by the protection domains in the access
control context stored in that URLClassLoader instance (this access
control context was snapshotted by URLClassLoader's constructor).  This
access control context's domain's may not include permissions to read
from where the parent WebappClassLoader looks for classes and
resources-- in the case of an RMI class loader, for example, it
typically does not include such permissions, because it will only
include permissions to read from the loader's own URLs.

When this defineClass operation causes a recursive loading operation
(such as to load a supertype of the class being defined), delegation to
the parent WebappClassLoader results in its findClassInternal method
being invoked.  Because that method does not execute as a privileged
operation itself, its attempt to read the class definition from some
location (such as the .../WEB-INF/classes/ tree) fails with a security
exception, because the child loader's privileged operation is still in
force.

[Because the access control context used by RMI class loaders uses a
domain with a set of permissions that were assembled synthetically, it
is impossible to grant the necessary permissions through the security
policy (as a workaround), except by granting them to all code, which is
clearly undesirable.]

The fix is a relatively simple one.
First we need to add a private class variable to hold the loaders context:

private AccessControlContext acc;

next we need to retrieve and store this context in the Class's two constructors:

    public WebappClassLoader() {
    ...
        if (securityManager != null) {
            refreshPolicy();
        }
        acc = AccessController.getContext();    // see URLClassLoader
 >>>----^ add this line above
    }^M


Finally we need to wrap the logic of the findClassInternal() method in a
doPriveleged operation:

    protected Class findClassInternal(final String name)
        throws ClassNotFoundException {

        try {
            return (Class)
                AccessController.doPrivileged( new PrivilegedExceptionAction() {
                    public Object run() throws ClassNotFoundException {
                        if (!validate(name))
                            throw new ClassNotFoundException(name);

                        Etc...
            }, acc);
        } catch (java.security.PrivilegedActionException pae) {
            throw (ClassNotFoundException) pae.getException();
        }
    }


We have developed a simple servlet that employs the RMIClassloader
to demonstrate the problem.  We've tested the fixes supplied above and
they do correct the problem.  We would be happy to furnish the test
to you, if you like.

---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to