Bytecode Verification


When a class loader presents the bytecodes of a newly loaded Java platform class to the virtual machine, these bytecodes are first inspected by a verifier. The verifier checks that the instructions cannot perform actions that are obviously damaging. All classes except for system classes are verified. You can, however, deactivate verification with the undocumented -noverify option.

For example,

 java -noverify Hello 

Here are some of the checks that the verifier carries out:

  • That variables are initialized before they are used

  • That method calls match the types of object references

  • That rules for accessing private data and methods are not violated

  • That local variable accesses fall within the runtime stack

  • That the runtime stack does not overflow

If any of these checks fails, then the class is considered corrupted and will not be loaded.

NOTE

If you are familiar with Gödel's theorem, you may wonder how the verifier can prove that a class file is free from type mismatches, uninitialized variables, and stack overflows. Gödel's theorem states that it is impossible to design algorithms whose inputs are program files and whose output is a Boolean value that states whether the input program has a particular property (such as being free from stack overflows). Is this a conflict between the public relations department at Sun Microsystems and the laws of logic? Noin fact, the verifier is not a decision algorithm in the sense of Gödel. If the verifier accepts a program, it is indeed safe. However, the verifier may reject many programs even though they would actually be safe.


This strict verification is an important security consideration. Accidental errors, such as uninitialized variables, can easily wreak havoc if they are not caught. More important, in the wide open world of the Internet, you must be protected against malicious programmers who create evil effects on purpose. For example, by modifying values on the runtime stack or by writing to the private data fields of system objects, a program can break through the security system of a browser.

You may wonder, however, why a special verifier checks all these features. After all, the compiler would never allow you to generate a class file in which an uninitialized variable is used or in which a private data field is accessed from another class. Indeed, a class file generated by a compiler for the Java programming language always passes verification. However, the bytecode format used in the class files is well documented, and it is an easy matter for someone with some experience in assembly programming and a hex editor to manually produce a class file that contains valid but unsafe instructions for the Java virtual machine. Once again, keep in mind that the verifier is always guarding against maliciously altered class files, not just checking the class files produced by a compiler.

Here's an example of how to construct such an altered class file. We start with the program VerifierTest.java of Example 9-3. This is a simple program that calls a method and displays the method result. The program can be run both as a console program and as an applet. The fun method itself just computes 1 + 2.

 static int fun() {    int m;    int n;    m = 1;    n = 2;    int r = m + n;    return r; } 

As an experiment, try to compile the following modification of this program:

 static int fun() {    int m = 1;    int n;    m = 1;    m = 2;    int r = m + n;    return r; } 

In this case, n is not initialized, and it could have any random value. Of course, the compiler detects that problem and refuses to compile the program. To create a bad class file, we have to work a little harder. First, run the javap program to find out how the compiler translates the fun method. The command

 javap -c VerifierTest 

shows the bytecodes in the class file in mnemonic form.

 Method int fun()    0 iconst_1    1 istore_0    2 iconst_2    3 istore_1    4 iload_0    5 iload_1    6 iadd    7 istore_2    8 iload_2    9 ireturn 

We use a hex editor to change instruction 3 from istore_1 to istore_0. That is, local variable 0 (which is m) is initialized twice, and local variable 1 (which is n) is not initialized at all. We need to know the hexadecimal values for these instructions. These values are readily available from The Java Virtual Machine Specification by Tim Lindholm and Frank Yellin [Addison-Wesley 1999].

 0 iconst_1 04 1 istore_0 3B 2 iconst_2 05 3 istore_1 3C 4 iload_0  1A 5 iload_1  1B 6 iadd     60 7 istore_2 3D 8 iload_2  1C 9 ireturn  AC 

You can use a hex editor (such as DataWorkshop, which you can download from http://www.dataworkshop.de) to carry out the modification. Or, of course, you can use emacs in hexl-mode. In Figure 9-2, you see the class file VerifierTest.class loaded into DataWorkshop, with the bytecodes of the fun method highlighted.

Figure 9-2. Modifying bytecodes with a hex editor


Change 3C to 3B and save the class file. Then try running the VerifierTest program. You get an error message:

[View full width]

Exception in thread "main" java.lang.VerifyError: (class: VerifierTest, method:fun signature: ()I) Accessing value from uninitialized register 1

That is goodthe virtual machine detected our modification.

Now run the program with the -noverify (or -Xverify:none) option.

 java -noverify VerifierTest 

The fun method returns a seemingly random value. This is actually 2 plus the value that happened to be stored in the variable n, which never was initialized. Here is a typical printout:

 1 + 2 = 15102330 

To see how browsers handle verification, we wrote this program to run either as an application or an applet. Load the applet into a browser, using a file URL such as

 file:///C:/CoreJavaBook/v2ch9/VerifierTest/VerifierTest.html 

You then see an error message displayed indicating that verification has failed (see Figure 9-3).

Figure 9-3. Loading a corrupted class file raises a method verification error


NOTE

A curious hole in the verifier in the Java virtual machine has been known by many people for a long time but persists for compatibility. Suppose you have two class files A.java and B.java like this:

 public class A { public int field; } public class B {    public static void main(String[] args)    {       System.out.println(new A().field);    } } 

This program compiles and runs, of course. Now edit only the file A.java to make field private. Recompile only that file. The resulting program should fail verification since B now attempts to access a private field of A. However, up to JDK 5.0, the program will run and merrily access the private field. Only if you run the Java virtual machine with the -verify option will the error be caught.

The reason is backward compatibility with an obscure and ill-considered optimization in JDK 1.0see http://bugs.sun.com/developer/bugParade/bugs/4030988.html. This flaw is not considered a security risk because only classes loaded from the local file system are exempt from verification.


Example 9-3. VerifierTest.java
  1. import java.awt.*;  2. import java.applet.*;  3.  4. /**  5.    This application demonstrates the bytecode verifier of  6.    the virtual machine. If you use a hex editor to modify the  7.    class file, then the virtual machine should detect the  8.    tampering.  9. */ 10. public class VerifierTest extends Applet 11. { 12.    public static void main(String[] args) 13.    { 14.       System.out.println("1 + 2 == " + fun()); 15.    } 16. 17.    /** 18.       A function that computes 1 + 2 19.       @return 3, if the code has not been corrupted 20.    */ 21.    public static int fun() 22.    { 23.       int m; 24.       int n; 25.       m = 1; 26.       n = 2; 27.       // use hex editor to change to "m = 2" in class file 28.       int r = m + n; 29.       return r; 30.    } 31. 32.    public void paint(Graphics g) 33.    { 34.       g.drawString("1 + 2 == " + fun(), 20, 20); 35.    } 36. } 



    Core JavaT 2 Volume II - Advanced Features
    Building an On Demand Computing Environment with IBM: How to Optimize Your Current Infrastructure for Today and Tomorrow (MaxFacts Guidebook series)
    ISBN: 193164411X
    EAN: 2147483647
    Year: 2003
    Pages: 156
    Authors: Jim Hoskins

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net