Secure Coding mailing list archives

By default, the Verifier is disabled on .Net and Java


From: cradle at umd.edu (David Eisner)
Date: Thu, 04 May 2006 13:38:35 -0400

Dinis Cruz wrote:
Ok, I just did some further tests and I think I can say that Java
(version 1.5.0_06) has similar verification issues to the ones I
discovered on the .Net Framework (see links in my previous post).
[...]
This should prove that the verifier is not enabled by default on java
files loaded from the local computer.

First, apologies to Dinis and Kevin for the mis-attribution.

I agree, based on the various experiments, it looks like the bytecode
verifier is still not enabled by default for locally loaded class
files.  I'm not sure why my randomly modified HelloWorld.class file
behaved differently in the -verify / -noverify cases.  If I have more
time, I'll dig into it.

As mentioned, the source code for the jdk is available under the Sun
Community Source License. [1]  Unfortunately, this license doesn't
permit redistribution of code to non-licensees, so I'll just describe
what I found when I took a (non-exhaustive) look. 

j2se/src/share/bin/java.c:

java {-verify, -verifyremote, -noverify} are aliases for options passed
to the Java Hotspot Virtual Machine.  The options are aliased to
-Xverify:all, -Xverify:remote, and -Xverify:none, respectively.  These
options, in turn, don't seem to be documented, at least not in the VM
options documentation. [2]

Ah, but they are documented elsewhere. [3]  From that document:

----8<--------------
So, why all this verification? When class files are loaded (possibly
over the network or from an untrusted source) into a virtual machine,
there is no way of telling how its byte codes were generated. Basically,
in most cases, you can't trust the source of the Java class files. In
fact, the default verification setting in JRE 1.1 is to only verify
classes loaded from over the network. So, anything installed locally,
via CLASSPATH, is not verified. In JRE 1.1, if you have installed
something locally from a third-party and want to even verify that, too,
you can do that. Or, you can completely disable verification. The three
settings are all options to the java and jre commands:

    * -verifyremote - only perform verification process on classes
loaded over network (default)
    * -verify - verify everything
    * -noverify - verify nothing

In JDK 1.2, the default setting for verification is the same only verify
classes loaded over the network. However, the system classes are
specified from something other than the CLASSPATH environment variable,
and the command line options for verification differ. The system classes
are specified by either the System property sun.boot.class.path or the
command line option -Xbootclasspath:directories and jar files. This is
automatically set for you by the JRE and should never need to be set
manually. If you set it to add something yourself be sure to include the
original defaults, too. With regards to verification, if you wish to
manually control the level of verification, the options to the java
command with the V1.2 JRE are as follows:

    * -Xverify:remote - only perform verification process on classes
loaded over network (default)
    * -Xverify:all - verify everything
    * -Xverify:none - verify nothing

If a verification error is encountered, instead of the JRE reporting a
verification error or throwing an exception, it reports a can't find
error, like: Can't find class MyClass.
----8<--------------


On the other hand, this message from the java-security mailing list
archives [4] (from July 2001) seems to say something else:

----8<--------------
The "system classes" such as those in java.* that are contained in
rt.jar are loaded by the bootstrap class loader built-in to the Java
Virtual Machine. In Jave 2, the next class loader searched for classes
is the extension class loader which looks for classes in the jar files
in the lib/ext directory where the Java Runtime Environment is
installed. The so-called "system class loader" actually loads the
application classes found from the -classpath command line argument or
the CLASSPATH environment variable. Yes, the name "system class loader"
is confusing. It is named that way for historical reasons when both core
system classes as well as application classes were all loaded by the
bootstrap class loader in JDK 1.1.


I thought that, by default, the Java API classes (rt.jar) are the only
ones
that dont go thru the ByteCode Verifier?

        You are correct again. By default, all classes go through the
bytecode verifier except for those loaded by the bootstrap class loader.
You can change this behavior through the use of command line arguments.
This is because all classes except for those loaded by the bootstrap
class loader can by granted fine-grained security permissions. In order
to prevent those classes from cheating and trying to get more
permissions than they have been granted we need to verify them. Classes
loaded by the bootstrap class loader are always granted "AllPermission"
and cannot be granted fewer permissions. These classes are trusted as
part of the core Java runtime. Therefore there is no need to verify them
at runtime.
----8<--------------


This seems to jibe with what's in the Hotspot VM source code: If you're
curious, take a look at

jdk-1_5_0_scsl/hotspot/src/share/vm/runtime/arguments.cpp   and
jdk-1_5_0_scsl/hotspot/src/share/vm/runtime/globals.hpp
jdk-1_5_0_scsl/hotspot/src/share/vm/runtime/verifier.cpp  (start with
Verifier::verify_byte_codes)

paying attention to the BytecodeVerificationRemote and
BytecodeVerificationRemote booleans.  Semantically, "Local" seems to
mean the class loader for the class is null, and "Remote" means it
isn't.  Consulting the Classs.getClassLoader() public api documentation [5]:

"Returns the class loader for the class. Some implementations may use
null to represent the bootstrap class loader. This method will return
null in such implementations if this class was loaded by the bootstrap
class loader."

So this would seem to suggest that non-bootstrap classes *are* bytecode
verified.  Here's another experiment:

----8<------------------
$ cat HelloWorld.java
public class HelloWorld {
    public static void main( String[] args ) {
        System.out.println( "HelloWorld class loader: " +
                             HelloWorld.class.getClassLoader() );

        System.out.println( "Math class loader: " +
                             Math.class.getClassLoader() );
        System.exit(0);
    }
}

$ java -cp . HelloWorld
HelloWorld class loader: sun.misc.Launcher$AppClassLoader at e39a3e
Math class loader: null

----8<------------------


What determines when access to a private member is illegal?  Is it, in
fact, the bytecode verifier? 

-David



[1] http://www.sun.com/software/communitysource/j2se/java2/download.xml
[2] http://java.sun.com/docs/hotspot/VMOptions.html
[3]
http://java.sun.com/developer/onlineTraining/Security/Fundamentals/Security.html
[4]
http://archives.java.sun.com/cgi-bin/wa?A2=ind0107&L=java-security&D=0&P=1305
[5]
http://java.sun.com/j2se/1.5.0/docs/api/java/lang/Class.html#getClassLoader()



Current thread: