On Dec 6, 2016, at 1:04 PM, Alan Bateman <alan.bate...@oracle.com> wrote:
> 
> The reason that java.lang.invoke checks readability is because it's aligned 
> with bytecode. It would be a significant change if the access checks in 
> java.lang.invoke differed to bytecode.

The CONSTANT_MethodHandle constants very closely align with bytecode behavior, 
in the same class-file as the hypothetical bytecodes; should they respect 
read-edges?  Yes.

The Lookup.find* API parallels those constants, with as little divergence as 
possible.  Respect read-edges there?  Yes again.

Bytecode behavior alignment means that anything you can do by loading a 
classfile (or anon-class) next to the target class can also be done by a method 
handle.  Should such aux. classes respect read-edges?  Of course.

Diverging behavior between the above three access points (to bytecode 
behaviors) is possible but undesirable.  It would make refactoring operations 
and security analysis more painful.

On the other hand, there are reasons why Core Reflection ignores read-edges.  I 
suppose they are rooted in the dynamic, ad hoc, late-bound nature of reflective 
usage, as opposed to statically bound behavior attached to a particular bundle 
of bytecodes.  MH usage is often static but sometimes ad hoc.  Some MH use 
cases are:

- dynamic language, compiled call sites (S)
- dynamic language, interpreted call sites (S?)
- lambda capture (S)
- string concat (S)
- future use of indy by javac (S)
- unit tests for APIs (D?)
- optimization of Core Reflection calls (D)

Anything marked (S) is tightly coupled to a class file, *not* ad hoc, and must 
respect read-edges.  (IMO read-edges are not a security feature but a help to 
debugging unexpectedly emergent dependencies at run time.)  There are probably 
more (D) cases I'm missing.

For that last case (D) the read-edge check by Lookup can be worked around by 
performing the lookup in Core Reflection, and then using Lookup.unreflect*.  I 
think we should consider relaxing the read-edge check *just* for that case, 
allowable since Lookup.unreflect* is not precisely coupled to BC behavior.  
That would leave the Lookup.find* and CONSTANT_MH access points unchanged 
(strongly coupled to BC behavior).

I think one reason Core Reflection requires a loophole for reads-edges is that 
it does not contain any reliable mechanism for delegated access checks.  (This 
is also why the calls are slow:  The checks are done in a hacky @CS manner.)  
Since MH-using code must always keep track of the Lookup for the principal, 
that principal's reads-edges can be expected to "make sense", and a failure to 
read is something that (should be) less likely than with Core Reflection, where 
there cannot be any accurate knowledge of the principal (whose reads-edges are 
the ones that matter).

So, that's the theory that makes sense to me.  What's the practice?  :-)

— John

Reply via email to