Class loaders allow an a Java application to be dynamically extend a Java application extended at runtime by loading classes. The JVM tracks, for For each class that is loaded, which specific the JVM tracks the class loader performed the loadthat was used to load the class. When a loaded class first refers to another class, the virtual machine requests that the referenced class be loaded by the same class loader used to load the referencing class.
Java's class loader architecture controls interaction between code loaded from different sources by allowing the use of different class loaders. This separation of class loaders is fundamental to the separation of code; it prevents malicious code from gaining access to and subverting trusted code. Hence, it is important to preserve this separation. A class loader that loads untrusted code must be prevented from interacting with trusted code that invokes any of the methods from the following table:
Methods |
---|
|
|
|
|
|
|
|
|
|
|
|
|
The In practice, the trusted code's class loader frequently allows these methods to be invoked , although an whereas untrusted code's class loader may lack these privileges. However, when the untrusted code's class loader delegates to the trusted code's class loader, the untrusted code gains visibility to the trusted code. In the absence of such a delegation relationship, the class loaders would ensure namespace separation; consequently, the untrusted code would be unable to observe members or to invoke methods belonging to the trusted code.
...
With the exception of the loadLibrary()
and load()
methods, the tabulated methods fail to perform any security manager checks. The loadLibrary()
and load()
APIs are typically used from within a doPrivileged
block; in that case, unprivileged callers can directly invoke them without requiring any special permissions. Consequently, the security manager checks are curtailed at the immediate caller; the . The security manager fails to examine the entire call stack and so fails to provide enhanced enhance security. Accepting tainted inputs from untrusted code and allowing them to be used by these APIs may expose vulnerabilities.
...
Java 1.7.0u10 was exploited in January 2013 because of several vulnerabilities. One vulnerability in the MBeanInstantiator
class granted unprivileged code the ability to access any class regardless of the current security policy or accessability of the classaccessibility rules. The MBeanInstantiator.findClass()
method could be invoked with any string and would attempt to return a Class
object. This method delegated its work to the loadClass()
method, whose source code is shown:
Code Block | ||||
---|---|---|---|---|
| ||||
/** * Load a class with the specified loader, or with this object * class loader if the specified loader is null. **/ static Class<?> loadClass(String className, ClassLoader loader) throws ReflectionException { Class<?> theClass; if (className == null) { throw new RuntimeOperationsException(new IllegalArgumentException("The class name cannot be null"), "Exception occurred during object instantiation"); } try { if (loader == null) loader = MBeanInstantiator.class.getClassLoader(); if (loader != null) { theClass = Class.forName(className, false, loader); } else { theClass = Class.forName(className); } } catch (ClassNotFoundException e) { throw new ReflectionException(e, "The MBean class could not be loaded"); } return theClass; } |
This method clearly delegates work delegates the task of dynamically loading the specified class to the Class.forName()
method. The forName()
method only checks the immediate caller , and since it is the (trusted) loadClass()
method, happily returns a sensitive Class
objectand uses its trusted state to return a Class
object of a potentially sensitive class.
Compliant Solution (CVE-2013-0422)
...
Code Block | ||||
---|---|---|---|---|
| ||||
// ... if (className == null) { throw new RuntimeOperationsException(new IllegalArgumentException("The class name cannot be null"), "Exception occurred during object instantiation"); } ReflectUtil.checkPackageAccess(className); try { if (loader == null) // ... |
Noncompliant Code Example
...