Cafe au Lait Special Report: Access Violations

Reports

Thursday, June 29, 2000

Sudarshan N. Mogasale of Geometric Software Solution Co. Ltd has uncovered a possibly related and even more dangerous problem. The JDK 1.3 For Windows NT does not check access specifiers at runtime. This allows you to access private data with either a hacked compiler, direct editing of byte code, or a simple recompile. Consider these two programs:

public class Outside {

  public static void main(String[] args) {
  
    Inside inside = new Inside();
    inside.print();
    inside.value = 42;
    inside.print();
  
  }

}
public class Inside {

  private int value = 23;
  
  private void print() {
    System.out.println(value);
  }

}

Clearly, Outside should neither compile nor run because it can't access the private value field in Inside, and indeed it doesn't. However you can trick the compiler into compiling it and the virtual machine into running it!

To do this, first make value and print() public like this:

public class Inside {

  public int value = 23;
  
  public void print() {
    System.out.println(value);
  }

}

Now compile both files and run Outside. This is what you expect and what you get:

D:\JAVA\private>java Outside
23
42
So far, so good. No surprises. However, now change value and print() back to private like this:

public class Inside {

  private int value = 23;
  
  private void print() {
    System.out.println(value);
  }

}

Recompile only Inside.java, not Outside.java. The run Outside like this

D:\JAVA\private>javac Inside.java

D:\JAVA\private>java Outside
23
42

Outside can now access and change the private value field in Inside! This shouldn't happen! Outside should throw an IllegalAccessError instead. Although the steps outlined here, require access to the source code of the class whose private data you're illegally accessing, it's not that much harder to do it without the source code. You just have to know a little bit about Java byte code hacking. This is a major security hole that opens up many attacks. I don't know if it's been reported before. I've verified it on NT 4.0 using Sun's latest JDK 1.3. Mogasale has tested it on JDK 1.2.2 and 1.3. He also says this problem does not arise on JDK 1.1.7 for Solaris. I do not yet know if this hole is present in any browser VMs, though I suspect it only arises in Java 1.2 and later. More reports and tests from different VMs would be helpful. You can send your results to my usual address, elharo@metalab.unc.edu and I'll summarize here tomorrow. I'd especially like to know if this occurs in either JDK 1.2.2 or 1.3 on Solaris, and whether anyone can find a report of this in the Java Developer Connection Bug Parade. I'd also like to know whether or not the various browser VMs are vulnerable to this.

Friday, June 30, 2000

The problem Sudarshan N. Mogasale reported whereby classes get to access the private members of other classes turns out to be a feature, not a bug, at least according to Sun. (I'm still not convinced.) Access protection is enforced by the byte code verifier which is turned off by default for classes loaded from the local file system. It can be turned on by using the undocumented -verify or -Xverify:all options to the java interpreter. For example,

D:\JAVA\private>java Outside
23
42

D:\JAVA\private<java -verify Outside
Exception in thread "main" java.lang.IllegalAccessError: try to access method 
Inside.print()V from class Outside
        at Outside.main(Outside.java:6)

As I originally suspected might be the case, this turns out to be a known bug in the Java Developer Connection Bug Database, specifically number 4030988. What I didn't suspect was that this was originally reported over three years ago against Java 1.1b3 and is "Closed, will not be fixed". (Side note: with over four million bugs in the database, it's no surprise it's getting hard to locate anything. We really, really need to devleop some better search algorithms. Boolean and full-text search just aren't cutting the mustard anymore, even within the restricted space of Java bugs.)

I've received conflicting reports about why this behavior is the way it is. The most likely possibility seems to be for compatibility with classes generated by some older, incorrect compilers that required direct access to private members to support inner classes. This suggests that using the -Xfuture option to the interpreter should also fix the problem because this option enforces all constraints that JavaSoft expects to enforce at some point in the indefinite future, such as forbidding access to private members; and indeed this option does fix the problem.

At the very least, this means that applets (which do verify untrusted byte code) shouldn't have any security problems as a result of this bug--excuse me, feature. However, I still think that byte code verification should be turned on by default, at least for those issues which can be produced by the normal Java compilation process. An option to turn off verification is perhaps reasonable. leaving it turned off by default until someone trips over it is not. For instance, in a pure application environment one programmer on a team may be unintentionally using a field or method another programmer on the same team thinks is hidden. I don't know that every byte code verification needs to be made for local classes, but access protection is pretty fundamental. Some Java 1.1 and 1.2 VMs do notice the problem, and won't run the test program with or without verification. Others don't and run it happily.


Ralph Prescott

Date: Wed, 05 Jul 2000 09:13:15 -0400
From: "Ralph Prescott" <ralph_prescott@xelus.com<
Organization: Xelus
Subject: Re: AccessToPrivates

Good summary this morning.

"Undocumented" is right! You have to poke through the source files of the launcher programs and the VM source code to figure out what's actually happening. Unfortunately the launcher programs that now ship with the JDK only tell you the mapping between "published" arguments and the implementation internal "-X" arguments which are passed into JNI_CreateJavaVM.

As an example: -Xfuture simply maps to -Xverify:all

Then of courese you have to track into the actual implementation to see what internal flags are being set from all those -X arguments and then see how it uses those flags during operation.

One other thing to keep in mind is the difference between class file "format" verification and access checks. They are two different things. Various and sundry things can kick out at class load time while things like field and method access violation may not happen until the first time they are accessed. This is a good compromize to faster startup but of course leaves potential undiscoverd bugs.

c'est la vie

External Links and Reports


If you'd like to add your own comments on this topic, write them up and email them to elharo@metalab.unc.edu. I reserve the right to edit for style and content as well as to select which reports are and are not posted. Generally speaking, the most comprehensive, accurate, and interesting reports will be posted; especially those that introduce new information not already included here. Please be sure to tell me that what you send is intended for publication. By default, I assume that personal email is a private communication and will not republish it unless told otherwise. At the same time, if you specifically wish to remain anonymous, tell me that too. Otherwise I'll assume it's permissible to cite you as the source of a particular piece of information or story. Thanks!


Cafe au Lait Home | Java Books | Java Trade Shows | Java Course Notes | Java FAQ | Java Tutorial | Java User Groups | Java Mailing Lists | Java Questions | Java Quotes

Copyright 2000 Elliotte Rusty Harold, elharo@metalab.unc.edu
Individual reports copyright by their respective authors.
Last Modified on July 11, 2000