On 09/19/2013 09:55 PM, David M. Lloyd wrote:
Imagine:
// this throws IllegalAccessException. If it didn't...
MethodHandle mh = MethodHandles.lookup()
.in(String.class)
.findVirtual(
Field.class,
"get",
MethodType.methodType(Object.class, Object.class)
);
Field valueField = String.class.getDeclaredField("value");
String abc = "abc";
// ... then the following would invoke: valueField.get(abc) and
pretend that
// it was invoked from the String class, which would succeed...
char[] abcArray = (char[])(Object) mh.invokeExact(valueField,
(Object) abc);
// ...and you could observe the following:
abcArray[0] = 'A';
assert abc.charAt(0) == 'A';
This must have changed since JDK 7 because I don't see any of this
behavior with the classic getCallerClass(int) method. In other words
using "in" does not appear to affect the frames reported by
getCallerClass(int) (or SecurityManager.getClassContext() or
Thread.getStackTrace()) at all.
It only affects frames seen in caller sensitive methods. In other
methods, the JDK7 reported caller is the one invoking the MH, I think,
but that's not important, since other methods are not caller sensitive.
In JDK8 you can't even get the caller unless you are in the @CS
annotated method.
It looks like this new behavior is a result of @CallerSensitive and
changes associated with it (in particular those weird pseudo-class
names are not reported in 7); I'd say the fatal flaw exposed here is
in those changes, not in the original method behavior. It seems like
we've gone way off course if this is the case.
I think the behavior is equivalent. In JDK7 all caller-sensitive methods
are maintained as a hard-coded list/switch inside MHs implementation.
They are marked with @CS annotation in JDK8 instead, which is easier to
maintain.
Especially consider that SecurityManager.getClassContext() is a
supported, non-deprecated API designed for the express purpose of
access checking, which (as far as I can test) works similarly to
getCallerClass(int). If method handles could spoof callers in this
way then we've blown yet another massive hole in Java security.
They can't spoof callers. As you can see in above example, such spoofing
look-ups of @CS methods are prevented.
--
- DML
Regards, Peter