Friday, May 26, 2006

Java Tip #10 - Constructor Exceptions are Evil

I saw this in the Secure Coding Antipatterns session at JavaOne 2006. It might scare the hell out of you.

Suppose I have the following class Foo and the constructor of Foo throws an exception. This might be due to some kind of security constraint or an invalid state. Suppose we don't anyone unauthorized to call the doEvil() method.

public class Foo {
public Foo() {
System.out.println("constructing foo: " + this);
throw new RuntimeException();
}
public void doEvil() {
System.out.println("Evil!Evil!Evil");
}
}

In the following code, is there anyway for me to get access to Foo if the constructor throws an exception?

try {
Foo x = new Foo(); // <-- exception thrown here }
catch Exception(e)
{ ... }


I didn't see it at 1st, but there at least one way to do it. If Foo isn't final, I can subclass Foo and get access to the instance.

public class MyFoo extends Foo {
public static Foo x;
@Override
protected void finalize() throws Throwable {
x = this;
}
}

Now I construct a MyFoo instance, call System.gc() and runFinalization().

try {
Foo x = new MyFoo();
} catch(Exception e) {
System.out.println(""+e);
}
System.gc();
System.runFinalization();
System.out.println("MyFoo instance: " + MyFoo.x);
MyFoo.x.doEvil();

I get the following output.

constructing foo: MyFoo@923e30
java.lang.RuntimeException
MyFoo instance: MyFoo@923e30
Evil!Evil!Evil

The moral of this story is to use the final keyword if you want to prevent incomplete instances from being accessible. The presenters of the session also suggested using a "initialized" field that is set as the last line of the constructor. A critical method could validate this field before doing work. I think final is a better solution.

Enjoy.

BBB

4 Comments:

Anonymous Anonymous said...

Can this be done without finalize()? Also, seems like an unlikely accidental bug, so I'm not too worried about it from that front. Can you construct a case where it presents something more nefarious like a security issue or whatnot? (I guess I'm too lazy to think through that myself.)

In any case, thanks much for the info. I'm glad at least to be aware of the possibility.

10:35 AM  
Blogger swankjesse said...

Ok, I've got another sick way to hack this, but I'll have to slightly change the constructor:
public Foo() {
System.out.print("constructing foo: ");
System.out.println(this);
throw new RuntimeException();
}

Now here's the hack. First a hacked printstream class:
class HackedPrintStream extends PrintStream {
public void println(Object o) {
Foo myFoo = (Foo)o;
// badness now
}
}

.. and now set it up:
System.setOut(new HackedPrintStream());

The new moral of the story? Security is very hard.

11:46 PM  
Anonymous Paul Clapham said...

Fortunately Firefox lets me turn off a web page's stylesheet. Reading code in pale-gray on white background is almost impossible.

2:05 PM  
Blogger Billy Bob Bain said...

Don't know why blogger was delivering that style. I am pretty sure it was black on black. I will take a look though.

12:00 PM  

Post a Comment

<< Home