Tacit Records: The Java Class Loader
The class loader is an integral part of the Java security architecture. Class loaders separate name spaces to prevent code corruption and name clash problems. They protect the boundaries of the core Java class packages. They establish the protected domains for a loaded class, the basis for runtime authorization. They enforce a search order that prevents core and local classes from being replaced by classes from less trusted sources. The class loader is part of the Java type-safety strategy along with the verifier and runtime security checks.
Java is also a dynamically linked system. This means that all code is linked into the executing JVM at runtime, unlike most other languages which link during compile time. The ClassLoader is responsible for performing the dynamic linking.
Trusted versus Untrusted
The class is the smallest unit loaded by a class loader. A class is a machine independent binary representation called a class file. Class files may contain bytecode and symbolic references that need to be resolved at link time.
Java classes can be loaded from just about anywhere. Code normally comes from the Core classes, installed JVM extensions, classes stored on a local file system, or classes retrieved from a Web server or URL location.
Class loaders are specifically responsible for determining between untrusted and trusted classes. This is a difficult job because not all class files are from the same source, and they may not be under the operating systems control.
|If the loader cannot find the class among the Java API or JVM extensions, then it knows that the class is not in a trusted location, and therefore will load the class as an array of bytes and send the array to be verified by the class verifier before construction.|
Trusted classes are basically ones the JVM can assume are safe, and therefore it executes them more quickly by skipping other security processes. Only Java runtime environment classes are fully trusted. All other classes are subject to verification and are considered untrusted. Java uses its boot class path to look for these classes.
The Loading Process
Before Java can run a program, it needs to locate the classes that make up the program and load them into memory. Traditionally the operating system, which has access to low level input and output, memory allocation, and the file system, does this.
When a class is referenced, the JVM invokes the class loader associated with the request to locate and load the class. Which class loader it uses depends on the request. The class loader called checks first to see if the class has already loaded (It is critical for type safety that the same class is not loaded more than once by the same class loader.) If it has been loaded it checks with securitymanager to see if the program has permissions to access the requested class. If not, then a security exception is thrown, otherwise the loader returns a reference to the class.
If the class has not been loaded, the class loader still checks with security manager to see if the program has the appropriate permissions to create the class, and throws a security exception if it does not. If the program has the proper permissions, the loader searches for the class.
The loader typically looks for a class first via the core Java API and JVM extensions, checking there first to prevent core extensions from being overwritten. If the class is found, the class is loaded and a reference to it is returned.
If the loader cannot find the class among the Java API or JVM extensions, then it knows that the class is not in a trusted location, and therefore will load the class as an array of bytes and send the array to be verified by the class verifier before construction.
After a class loader loads a class, it becomes the class's defining class loader, and is responsible for loading further classes and linking. If the request to load a class is triggered by a reference from a class loaded by the class loader, it is also called to load the new class.
Standard Class Loaders
The Primordial Class Loader
Since each class loader is itself a class, the question as to which comes first is often asked. There is a primordial class loader, sometimes referred to as the bootstrap, null, internal, or default class loader. The primordial class loader is a built in part of the JVM, is written in native code (usually C), and is platform dependent. Classes loaded by the primordial class loader are not subject to the Java class verifier prior to execution (and are considered trusted). The primordial class loader loads the necessary files to initially bootstrap the JVM.
The SecureClassLoader is an extension of ClassLoader and a standard class loader within the JDK runtime library. The SecureClassLoader provides a base class that other ClassLoader types can extend to hook into Java's security system. It is an abstract class, and is not intended to be used directly, all other class loaders should instead extend from it. SecureClassLoader handles, among other things, checking with the security manager, calling the class file verifier, and setting up the protection domain.
The URLClassloader is an extension of SecureClassLoader. A new instance of URLCLassLoader is used when the first class of an application is being loaded.
When the first class of an applet is being loaded, a new instance of the AppletClassLoader is used. It is intended to be used by browsers to download and start applet bytecode.
A class that is wrapped around the loading of classes in the RMI runtime system.
sun.misc.Launcher$ExtClassLoaderAn extensions class loader, responsible for loading the Java extension classes.
Handles loading code from the java.class.path property
Alterations and improvements to the JDK have made custom class loaders less common. However, under the right circumstances they can still be extremely useful. Programmers need to be especially careful not to disrupt the security architecture when employing class loaders.
When customizing applet class loaders, realize that a Web browser can only use one class loader, which needs to be established at start up, and it cannot be extended, overloaded, overridden, or replaced. Applets also cannot reference their own class loader.
Custom class loaders should not allow any part of the trusted Java API library to be overwritten. Custom loaders should first try to delegate the loading to standard and parent loaders (up to the primordial, if possible) to ensure that this doesn't happen.
Loaders can be restricted by including a list of appropriate packages and having them deny loading other applications. Minimally, a loader should have a list of local packages that it should not be allowed to load.
- Gong, Li. Inside Java 2 Platform Security. Reading: Addison Wesley. 1999.
- Neward, Ted. Server Based Java Programming. Greenwich: Manning. 2000.
- Pistoia, Marco, et al. Java 2 Network Security. Upper Saddle River, Prentice Hall. 1999.
- Sun's Java Security FAQ
- Sun's Class Loader Overview
- Sun's overview Uses of Class Classloader
Thomas Gutschmidt is a freelance writer, in Bellevue, Wash., who also works for Widevine Technologies.