To kickstart the new year and in an attempt to get more writing done I think I'll try writing some shorter bits. This one's about the Java "final" keyword - it's different nuances and how they relate to security.
Final has meanings that are so distinct that I sometimes wonder if it wouldn't have been clearer to use several different keywords. Here are the meanings of the keyword final:
Final classes
Classes with the modifier final cannot be subclassed. If the instances of the class have a state, that state can change, static fields, etc, everything may be mutable. The final here only prohibits subclassing.
Final methods
Methods with the modifier final cannot be overwritten/overridden by subclasses. The methods can be used by subclasses, their output may differ from call to call, they just cannot be redefined in the subclasses. The method may be overloaded, because overloaded methods (methods with the same name, but different signature) are completely different methods in the eyes of the compiler and the runtime.
Final fields
The value for fields with the modifier final can only be set once.
In the case of primitive type fields, this means that if the value was set to (int) 91, then the value will remain 91. The compiler may take advantage of this knowledge and inline the value where it is being referred.
In the case of objects, if the field is set to reference an object, it will always reference that same object. If the object is mutable, the perceived and logical value of the object may change, only it's identity is guaranteed not to change.
Final method variables
Since method variables aren't accessible outside the method, the final keyword here is only for use of the compiler.
Security and final
Here's how these nuances of the final keyword relate to security:
Classes
Final classes are very restrictive; since you can't subclass them you can't make them Serializable and you can't override their functionality. As far as I can tell, there is no way around it either, the rule is absolute: if it's final, you can't override it.
Methods
Final methods, like the classes are very restrictive. At the most, you may be able to override another method that the final method calls and use that to alter the method's functioning.
Fields
Final fields are not such an obvious case; while you cannot redefine their value there are some interesting details about them.
Their value isn't always the same. If you can obtain access to an object before it's initializer has defined the value of the final field, the field will have it's uninitialized value which will be 0, false or null for numeric types, boolean types and object types respectively. Then once the initializer sets the value it will change to the defined value. That's a very minor detail, but security is all about knowing all the right minor details.
As stated, the field will always reference the same object, but the real value of that object is free to change. If the object contains fields, etc that can be accessed and whose value can be altered then the value of the object itself can be changed.
Arrays are a special type of mutable objects -- the array elements of a final array field can change. The array object itself will stay the same, and it's size or number of dimensions cannot change, but the element values are very much mutable.
A multidimensional array object is actually an array of objects with one less dimensions. Thus in the case of a final multidimensional array object, only the outermost array is really final; the inner arrays may change identity and size.
sun.misc.Unsafe
The reflection API is bound by the final keyword and if you try changing the value of a final field via reflection, you will run into an IllegalAccessException.
There is, however, one omnipotent class in the sun.misc package, called Unsafe, which directly write into memory, put int values into object fields and it is also able to rewrite values into final fields. You use the fieldOffset methods to determine the offset of a given field, and then you use one of the putXXX methods to set the value. Unsafe can also access private fields.
Saturday, January 23, 2010
Java "final" and security
Labels:
final,
final array,
final class,
final field,
final method,
java,
security
Subscribe to:
Post Comments (Atom)
2 comments:
Nice post on final usage.
If I'm not mistaken, since java 5, you can set final fields using standard reflection (and not relying on sun.misc.Unsafe). You just need to call setAccessible(true) before attempting to manipulate the field's data.
Based on this, the compiler won't be able to inline primitive final fields, because it's not guaranteed to keep the same value.
Jonas, thanks for the feedback.
Also thank you for correcting me. You are correct in that reflection with setAccessible(true) can indeed write into a final field. I had tested that before hitting publish, but it seems my test had a slight flaw in it. I tested with a static final field. And it seems that static final fields cannot be changed, even with setAccessible(true).
Regardless of all that, inlining does take place. I imagine the formatting will be awful, but imagine MAGIC_VALUE is a non-static final int field, with the value 91 -- the following:
System.out.println(MAGIC_VALUE);
Field f = Inline.class.getField("MAGIC_VALUE");
f.setAccessible(true);
f.set(this, 77);
System.out.println(MAGIC_VALUE);
prints
91
91
on my Java 6 (compiled with Eclipse JDT).
Post a Comment