Discussion: Prefer passing MethodHandles.Lookup over @CallerSensitive
Johannes Kuhn
info at j-kuhn.de
Fri Apr 21 20:58:17 UTC 2023
Hi,
to reiterate: I do not want to change existing APIs.
Instead having a discussion that can guide the introduction of new APIs
that may want to be @CS (but don't need to be).
On 21-Apr-23 21:30, mandy.chung at oracle.com wrote:
>
> On 4/21/23 6:44 AM, Johannes Kuhn wrote:
>> Hi,
>>
>> Instead of making new and existing methods @CallerSensitive, such
>> methods could instead take a MethodHandles.Lookup as method argument.
>>
>> Library authors are often told that they could ask their users to pass
>> a MethodHandles.Lookup to obtain internal access instead of using
>> things like AccessibleObject::setAccessible.
>>
>> I hope OpenJDK would follow that advice as well, IMHO the broader use
>> of MethodHandles.Lookup would make things easier for both OpenJDK
>> deverlopers & library authors.
>>
>> tl;dr: Have one @CallerSensitive method to rule them all:
>> MethodHandles.lookup()
>>
> Short answer is: It depends. The platform already has such an example:
> ConstantDesc::resolveConstantDesc takes the Lookup parameter as the
> resolution and access control context.
>
> Long answer is: caller-sensitiveness of @CS methods is used in several
> categories. It all depends.
>
> 1. security permission check: bypass SecurityManager permission checks
> depending on the immediate caller's class loader. Majority of @CS
> methods are in this category. This includes 3-arg Class::forName,
> Class::getClassLoader, ClassLoader::getSystemClassLoader,
> java.lang.reflect APIs as well as APIs that call these @CS methods on
> behalf of the caller such as
> javax.sql.rowset.serial.SerialJavaObject::getFields. >
> We should not introduce any new APIs in this category.
I agree on this.
>
> 2. Access check: core reflection API e.g. Field::setInt
>
> 3. Caller's context as the default: this includes 1-arg Class::forName,
> Resource::getBundle, ClassLoader::registerAsParallelCapable,
> Package::getPackages
>
> a) Existing APIs already take a context parameter. For example, non
> 1-arg variants of Class::forName and Resource::getBundle already take
> the ClassLoader parameter to provide the context. A variant to take
> Lookup parameter for this category is unnecessary and redundant.
>
> b) For APIs that don't provide a variant to take the context parameter,
> it may be reasonable to define a variant to take a context parameter
> (Lookup or other type more appropriate and align with the existing APIs).
Again, it is not my goal to change existing behavior - instead having a
discussion about this to guide *new* APIs if they should be @CS or take
the context as parameter.
>
> For this subcategory, I agree the APIs should take the context
> parameter. Lookup object would be appropriate if it's for access
> control context. In addition, defining an API deriving the context
> from the caller should carefully be evaluated and justified.
>
> 4. Validate APIs being called by a valid caller: IllegalCallerException
> thrown if an illegal caller is detected. This includes Module::addReads,
> addExports, and java.lang.foreign APIs etc. Making these APIs to take a
> Lookup parameter is less easier to use.
>
Those are already existing APIs.
As example, John Rose suggested in his "Value type companions,
encapsulated"[2] the addition of more @CS methods - this is where I see
the value of a discussion beforehand.
>> -----
>>
>> 1. Conceptually a @CallerSensitive method has a hidden parameter - the
>> caller class, which does not appear in source- or bytecode. A
>> MethodHandles.Lookup parameter is explicit.
>>
>> 2. Most @CallerSensitive methods are listed in the Secure Coding
>> Guidelines for Java SE[1]. When adding new @CallerSensitive methods it
>> should always be considered if those methods need to be listed in that
>> document as well.
>> This list should also not increase indefinitely, as each use of a
>> method listed there needs to be carefully checked to avoid security
>> vulnerabilities.
>> Using a method taking a MethodHandles.Lookup needs the same scrutiny -
>> but because of the explicit nature this is evident from looking at
>> use-site.
>
>
> These @CS methods are the ones that bypass SecurityManager permission
> checks depending on the immediate caller's class loader. We should not
> add any new CS method adding to this list.
There are several categories, for ClassLoader, Module...
The SecurityManager is only related for a subset of them.
(Strictly speaking, restricted methods from panama may also fall under
ACCESS-14)
>
>> 3. Methods that take an explicit MethodHandles.Lookup compose better
>> with other methods that do the same - for example, a library could
>> pass the lookup it received from its client to a core API, thereby
>> acting on behalf of the client.
>>
>> 4. When a @CallerSensitive method is looked up from
>> MethodHandles.Lookup, it needs to be bound to the caller.
>> This binding can be expensive in the worst case (load of an hidden
>> class + erasing the signature to ([Ljava/lang/Object;)Ljava/lang/Object;)
>>
> Yes but one hidden class per each caller class. This overhead only
> applies to MethodHandle::invokexxx and Method::invoke on a @CS method
> which does not have an CS adaptor (see @CallerSensitiveAdaptor).
>
> This overhead is not relevant to the bytecode invocation of @CS methods
> such as Class::forName.
>
Yes, this is all true - but there is still overhead.
It is simply an argument why @CS is more complicated (and maybe should
be avoided for future APIs?)
>> 5. Making existing methods @CallerSensitive can lead to small
>> backwards compatibility issues - as the public lookup can't lookup
>> those methods anymore.
>>
> Can you explain what you observe about this? Public lookup has access
> to public members of public classes in packages that are exported
> unconditionally. @CS should have no impact to public lookup.
>
>
This line works with Java 7 - 16:
MethodHandles.publicLookup().findStatic(System.class,
"setSecurityManager", MethodType.methodType(void.class,
SecurityManager.class));
In Java 17 System::setSecurityManager is now @CS - for a good reason -
but such a change can break existing code, which should be considered.
>> -----
>>
>> A @CallerSensitive method have one benefit over passing a
>> MethodHandles.Lookup: It has a nicer API.
>> This might be fine for the restricted methods that Panama introduces.
>>
>> New methods that need to take the caller into account could for
>> example add instead an overload that takes an explicit
>> MethodHandles.Lookup as argument. The one without that argument could
>> work as if `MethodHandles.publicLookup()` was passed to the other.
>>
>> -----
>>
>> Closing words:
>> This is my personal opinion, and might be totally wrong.
>> For now, my goal is just to start a discussion.
>>
>> I explicitly don't ask about changing existing @CallerSensitive methods.
>
>
> Good. The categories I described above hope will give more context and
> explain the considerations to have for new APIs.
>
> Mandy
>
>> - Johannes
>>
>> [1]:
>> https://www.oracle.com/java/technologies/javase/seccodeguide.html#9-8
[2]: https://cr.openjdk.org/~jrose/values/encapsulating-val.html
More information about the core-libs-dev
mailing list