The URLClassLoader doesn't save the security context in its contructors and it doesn't use it in every class and resource access as it should. As it is said in the Sun URLClassLoader documentation: "The AccessControlContext of the thread that created the instance of URLClassLoader will be used when subsequently loading classes and resources." http://java.sun.com/javase/6/docs/api/java/net/URLClassLoader.html It leads to bugs when opening files when the loaded classes haven't the read filePermissions on other codeBases.
Created attachment 20581 [details] patch saving and using the security contexts correctly in URLClassLoader
Comment on attachment 20581 [details] patch saving and using the security contexts correctly in URLClassLoader diff --git java/net/URLClassLoader.java java/net/URLClassLoader.java index 52d297a..0b3908a 100644 --- java/net/URLClassLoader.java +++ java/net/URLClassLoader.java @@ -61,6 +61,8 @@ import java.security.AccessController; import java.security.CodeSource; import java.security.PermissionCollection; import java.security.PrivilegedAction; +import java.security.PrivilegedExceptionAction; +import java.security.PrivilegedActionException; import java.security.SecureClassLoader; import java.security.cert.Certificate; import java.util.ArrayList; @@ -187,7 +189,12 @@ public class URLClassLoader extends SecureClassLoader { super(); this.factory = null; - this.securityContext = null; + final SecurityManager sm = System.getSecurityManager(); + if (sm != null) + this.securityContext = (AccessControlContext)sm.getSecurityContext(); + else + this.securityContext = null; + addURLs(urls); } @@ -213,7 +220,12 @@ public class URLClassLoader extends SecureClassLoader { super(parent); this.factory = null; - this.securityContext = null; + final SecurityManager sm = System.getSecurityManager(); + if (sm != null) + this.securityContext = (AccessControlContext)sm.getSecurityContext(); + else + this.securityContext = null; + addURLs(urls); } @@ -262,7 +274,12 @@ public class URLClassLoader extends SecureClassLoader throws SecurityException { super(parent); - this.securityContext = null; + final SecurityManager sm = System.getSecurityManager(); + if (sm != null) + this.securityContext = (AccessControlContext)sm.getSecurityContext(); + else + this.securityContext = null; + this.factory = factory; // If this factory is not yet in factoryCache, add it. factoryCache.add(factory); @@ -511,7 +528,38 @@ public class URLClassLoader extends SecureClassLoader protected Class<?> findClass(final String className) throws ClassNotFoundException { + Class result = null; + try + { + result = AccessController.doPrivileged + (new PrivilegedExceptionAction<Class>() + { + public Class run() + throws IOException + { + return findClassImpl(className); + } + }, this.securityContext); + } + catch (PrivilegedActionException e) + { + throw new ClassNotFoundException(className + " not found in " + this, e.getException()); + } + catch (RuntimeException e) + { + throw new ClassNotFoundException(className + " not found in " + this, e); + } + if (result != null) + return result; + else + throw new ClassNotFoundException(className + " not found in " + this); + } + + protected Class<?> findClassImpl(final String className) + throws IOException + { // Just try to find the resource by the (almost) same name + Class result = null; String resourceName = className.replace('.', '/') + ".class"; int max = urlinfos.size(); Resource resource = null; @@ -528,12 +576,10 @@ public class URLClassLoader extends SecureClassLoader resource = loader.getResource(resourceName); } if (resource == null) - throw new ClassNotFoundException(className + " not found in " + this); + return null; // Try to read the class data, create the CodeSource, Package and // construct the class (and watch out for those nasty IOExceptions) - try - { byte[] data; InputStream in = resource.getInputStream(); try @@ -598,23 +644,10 @@ public class URLClassLoader extends SecureClassLoader } // And finally construct the class! - SecurityManager sm = System.getSecurityManager(); - Class result = null; - if (sm != null && securityContext != null) - { - result = AccessController.doPrivileged - (new PrivilegedAction<Class>() - { - public Class run() - { - return defineClass(className, classData, - 0, classData.length, - source); - } - }, securityContext); - } - else - result = defineClass(className, classData, 0, classData.length, source); + result = defineClass(className, classData, 0, classData.length, source); + + if (result == null) + return null; // Avoid NullPointerExceptions. Certificate[] resourceCertificates = resource.getCertificates(); @@ -622,11 +655,6 @@ public class URLClassLoader extends SecureClassLoader super.setSigners(result, resourceCertificates); return result; - } - catch (IOException ioe) - { - throw new ClassNotFoundException(className + " not found in " + this, ioe); - } } // Cached String representation of this URLClassLoader @@ -670,20 +698,34 @@ public class URLClassLoader extends SecureClassLoader * @param resourceName the resource name to look for * @return the URLResource for the resource if found, null otherwise */ - private Resource findURLResource(String resourceName) + private Resource findURLResource(final String resourceName) { - int max = urlinfos.size(); - for (int i = 0; i < max; i++) + final int max = urlinfos.size(); + try { - URLLoader loader = (URLLoader) urlinfos.elementAt(i); - if (loader == null) - continue; - - Resource resource = loader.getResource(resourceName); - if (resource != null) - return resource; + return AccessController.doPrivileged + (new PrivilegedExceptionAction<Resource>() + { + public Resource run() + { + for (int i = 0; i < max; i++) + { + URLLoader loader = (URLLoader) urlinfos.elementAt(i); + if (loader == null) + continue; + + Resource resource = loader.getResource(resourceName); + if (resource != null) + return resource; + } + return null; + } + }, this.securityContext); + } + catch (PrivilegedActionException e) + { + return null; } - return null; } /** @@ -692,14 +734,66 @@ public class URLClassLoader extends SecureClassLoader * @param resourceName the resource name to look for * @return the URL if found, null otherwise */ - public URL findResource(String resourceName) + public URL findResource(final String resourceName) { - Resource resource = findURLResource(resourceName); - if (resource != null) - return resource.getURL(); + try + { + return AccessController.doPrivileged + (new PrivilegedExceptionAction<URL>() + { + public URL run() + { + Resource resource = findURLResource(resourceName); + if (resource != null) + return resource.getURL(); + + // Resource not found + return null; + } + }, this.securityContext); + } + catch (PrivilegedActionException e) + { + return null; + } + } - // Resource not found - return null; + /** + * Get a resource as stream using this classloader or one of its parents. + * First calls <code>getResource()</code> and if that returns a URL to + * the resource then it calls and returns the InputStream given by + * <code>URL.openStream()</code>. Use saved AccessControlContext to do so. + * + * @param name the name of the resource relative to this classloader + * @return an InputStream to the resource, or null + */ + public InputStream getResourceAsStream(final String name) + { + try + { + return AccessController.doPrivileged + (new PrivilegedExceptionAction<InputStream>() + { + public InputStream run() + { + try + { + URL url = getResource(name); + if (url == null) + return null; + return url.openStream(); + } + catch (IOException e) + { + return null; + } + } + }, this.securityContext); + } + catch (PrivilegedActionException e) + { + return null; + } } /** @@ -711,18 +805,38 @@ public class URLClassLoader extends SecureClassLoader * @exception IOException when an error occurs accessing one of the * locations */ - public Enumeration<URL> findResources(String resourceName) + public Enumeration<URL> findResources(final String resourceName) throws IOException { - Vector<URL> resources = new Vector<URL>(); - int max = urlinfos.size(); - for (int i = 0; i < max; i++) + final Vector<URL> resources = new Vector<URL>(); + final int max = urlinfos.size(); + + try + { + AccessController.doPrivileged + (new PrivilegedExceptionAction<Object>() + { + public Object run() + { + for (int i = 0; i < max; i++) + { + URLLoader loader = (URLLoader) urlinfos.elementAt(i); + Resource resource = loader.getResource(resourceName); + if (resource != null) + resources.add(resource.getURL()); + } + return null; + } + }, this.securityContext); + } + catch (PrivilegedActionException e) { - URLLoader loader = (URLLoader) urlinfos.elementAt(i); - Resource resource = loader.getResource(resourceName); - if (resource != null) - resources.add(resource.getURL()); + if (e.getException() instanceof IOException) + throw (IOException)e.getException(); + + return resources.elements(); } + return resources.elements(); }
Created attachment 20593 [details] patch saving and using the security contexts correctly in URLClassLoader, it also give privileges to system class loader This patch fixes a problem in URLClassLoader-privileged-patch which didn't give enough privileges to system class loader
Created attachment 20594 [details] patch saving and using the security contexts correctly in URLClassLoader, it also give privileges to system class loader This patch fixes a problem in URLClassLoader-privileged-patch which didn't give enough privileges to system class loader