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

Reply via email to