The Java runtime has two distinct ways of loading a new class. The default mechanism is to load a class from a file on the local machine. This mechanism does not need a ClassLoader. Another way of loading a class, such as over the network requires an associated ClassLoader which is responsible for converting the raw data of a class into an internal data structure representing the class.
The environment seen by a thread of execution running Java bytecodes can be visualized as a set of classes partitioned into separate name spaces. There is one name space for the local file system, and a separate name space for each network source.
When a class is imported from across the network it is placed into the
private name space associated with its origin. When a class references another
class, it is first looked for in the name space for the local system(built-in
classes), then in the name space of the referencing class. There is no way
that an imported class can "spoof" a built-in class. Built-in classes can
never accidentally reference classes in imported name spaces - they can only
reference such classes explicitly. Similarly, classes imported from different
sources are separated from each other.
The Java language and bytecode semantics are different which leads
to some security problems. The Java language requires that all constructors
call either another constructor of the same class, or a superclass constructor
as their first action. The system classes ClassLoader, SecurityManager,
and FileInputStream
all rely on this behavior for their
security. These classes have constructor which check if they are called from
an applet, and throw a SecurityException
if so. Unfortunately,
while the Java language prohibits the following code, the bytecode verifier
readily accepts its bytecode equivalent:
class CL extends ClassLoader {
CL() {
try { super(); }
catch (Exception e) {}
This allows us to build (partially uninitialized)
ClassLoaders, SecurityManagers,
and FileInputStreams
. ClassLoaders
do not have an instance variables. If the constructor is
executed once it will always run before the first applet is loaded. The result
of this attack is a fully initialized, customized and possibly
malicious ClassLoader
.
Java packages are normally named java.io, java.net
, etc. The
runtime system replaces each '.' with a '/' to map the package hierarchy
onto the file system hierarchy. It has been found that if the first character
of a package name was '/', the Java runtime system attempts to load code from
an absolute path. Thus, if an attacker could place compiled Java in any
file on the victim's system, (either through a shared file system or
via an incoming FTP directory) the attacker's code would be treated as trusted,
since it came from a local file. Trusted code is permitted to load dynamic
link libraries which can ignore the Java runtime and directly access the
operating system with the full privileges of the user.
Copyright © 1996 Virginia Polytechnic Institute & State University
All Rights Reserved
Vijay Sureshkumar
<vijay@csgrad.cs.vt.edu>
Last modified: Sun Oct 20 21:52:09 1996