Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Separate Painless Whitelist Loading from the Painless Definition #26540

Merged
merged 41 commits into from
Sep 18, 2017

Conversation

jdconrad
Copy link
Contributor

@jdconrad jdconrad commented Sep 7, 2017

Adds several small whitelist data structures and a new Whitelist class to separate the idea of loading a whitelist from the actual Painless Definition class. This is the first step of many in allowing users to define custom whitelists per context. Also supports the idea of loading multiple whitelists from different sources for a single context.

This is not as large a change as it looks -- ~250 lines are small formatting changes to the whitelist resource files. ~300 lines are documentation. (Sorry @rjernst)

@jdconrad jdconrad added :Plugin Lang Painless :Core/Infra/Scripting Scripting abstractions, Painless, and Mustache v6.1.0 v7.0.0 labels Sep 7, 2017
@jdconrad jdconrad requested a review from rjernst September 7, 2017 20:39
Copy link
Member

@rjernst rjernst left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @jdconrad, this looks good. I really like the simplifications to the txt file format. I left some suggestions. LGTM.

constant.clazz == float.class ||
constant.clazz == double.class ||
constant.clazz == String.class;
constant.clazz == byte.class ||
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this was better aligned before?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Intellij formatting error.

addStruct(whitelist.javaClassLoader, whitelistStruct);

Struct painlessStruct = structsMap.get(whitelistStruct.painlessTypeName);
javaClassesToPainlessStructs.put(painlessStruct.clazz, painlessStruct);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should fail if the put replaced an existing entry? Or rather, not replace if the mapping already exists (ie where a 2 different whiteslists are whitelisting methods on the same class). But surely they can't be allowed to have different names in painless for the same java class (one would overwrite the other here).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch, added an error.

structsMap.put("def", new Struct("def", Object.class, org.objectweb.asm.Type.getType(Object.class)));

try {
for (Whitelist whitelist : whitelists) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add a comment why we need this first loop over the classes, and then a second loop over all the methods/fields?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

}
} catch (Exception exception) {
throw new IllegalArgumentException("error loading whitelist(s) " + origin, exception);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this message accurate? Aren't the whitelists already loaded before this method is even called?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Message is accurate. The whitelist shouldn't be considered finished loading until the validation can be run.

assert currentClass != null;
addSignature(currentClass, line);
}
for (Struct painlessStruct : structsMap.values()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A short comment explaining what this loop does would be nice (to map the class hierarchy of java to whitelisted methods in subclasses in painless?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

javaHandle = MethodHandles.publicLookup().in(ownerStruct.clazz).unreflectConstructor(javaConstructor);
} catch (IllegalAccessException exception) {
throw new IllegalArgumentException("constructor not defined for owner struct [" + ownerStructName + "] " +
" with constructor parameters " + whitelistConstructor.painlessParameterTypeNames);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it intentional to drop the original exception? If so, please add a comment explaining why.

try {
javaMethodHandle = MethodHandles.publicLookup().in(javaImplClass).unreflect(javaMethod);
} catch (IllegalAccessException exception) {
throw new IllegalArgumentException("method handle not found for method with name " +
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same here, original exception is dropped.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch... was unintentional.

// sanity check, look for missing covariant/generic override
if (owner.clazz.isInterface() && child.clazz == Object.class) {
/*if (owner.clazz.isInterface() && child.clazz == Object.class) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this meant to be commented out? Please remove if it is no longer relevant.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I want to follow up in a different PR. Added a long explanation in a TODO. Will remove the elements after I've gone through them again. I think some are still relevant, but the code is buggy at this time.

* Structs will automatically extend other white-listed structs if the Java class they represent is a
* subclass of other structs including Java interfaces.
*/
public static final class Struct {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should consider (in a followup) renaming Struct to Class. We use the same name everywhere else as the java class (eg Method), so I think we should be consistent, and it will decrease confusion.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sure.

@jdconrad jdconrad merged commit c3746b2 into elastic:master Sep 18, 2017
@jdconrad
Copy link
Contributor Author

@rjernst Thanks for the review.

jasontedor added a commit to jasontedor/elasticsearch that referenced this pull request Sep 19, 2017
* master:
  added comment
  fix line length violation
  Moved the check to fetch phase. This basically means that we throw a better error message instead of an AOBE and not adding more restrictions.
  inner hits: Do not allow inner hits that use _source and have a non nested object field as parent
  Separate Painless Whitelist Loading from the Painless Definition (elastic#26540)
  convert more admin requests to writeable (elastic#26566)
  Handle release of 5.6.1
  Allow `InputStreamStreamInput` array size validation where applicable (elastic#26692)
  Update global checkpoint with permit after recovery
jasontedor added a commit to droberts195/elasticsearch that referenced this pull request Sep 19, 2017
* master: (278 commits)
  Move pre-6.0 node checkpoint to SequenceNumbers
  Invalid JSON request body caused endless loop (elastic#26680)
  added comment
  fix line length violation
  Moved the check to fetch phase. This basically means that we throw a better error message instead of an AOBE and not adding more restrictions.
  inner hits: Do not allow inner hits that use _source and have a non nested object field as parent
  Separate Painless Whitelist Loading from the Painless Definition (elastic#26540)
  convert more admin requests to writeable (elastic#26566)
  Handle release of 5.6.1
  Allow `InputStreamStreamInput` array size validation where applicable (elastic#26692)
  Update global checkpoint with permit after recovery
  Filter pre-6.0 nodes for checkpoint invariants
  Skip bad request REST test on pre-6.0
  Reenable BWC tests after disabling for backport
  Add global checkpoint tracking on the primary
  [Test] Fix reference/cat/allocation/line_8 test failure
  [Docs] improved description for fs.total.available_in_bytes (elastic#26657)
  Fix discovery-file plugin to use custom config path
  fix testSniffNodes to use the new error message
  Add check for invalid index in WildcardExpressionResolver (elastic#26409)
  ...
jasontedor added a commit to jasontedor/elasticsearch that referenced this pull request Sep 20, 2017
* master: (67 commits)
  Restoring from snapshot should force generation of a new history uuid (elastic#26694)
  test: Use a single primary shard so that the exception can caught in the same way
  Move pre-6.0 node checkpoint to SequenceNumbers
  Invalid JSON request body caused endless loop (elastic#26680)
  added comment
  fix line length violation
  Moved the check to fetch phase. This basically means that we throw a better error message instead of an AOBE and not adding more restrictions.
  inner hits: Do not allow inner hits that use _source and have a non nested object field as parent
  Separate Painless Whitelist Loading from the Painless Definition (elastic#26540)
  convert more admin requests to writeable (elastic#26566)
  Handle release of 5.6.1
  Allow `InputStreamStreamInput` array size validation where applicable (elastic#26692)
  Update global checkpoint with permit after recovery
  Filter pre-6.0 nodes for checkpoint invariants
  Skip bad request REST test on pre-6.0
  Reenable BWC tests after disabling for backport
  Add global checkpoint tracking on the primary
  [Test] Fix reference/cat/allocation/line_8 test failure
  [Docs] improved description for fs.total.available_in_bytes (elastic#26657)
  Fix discovery-file plugin to use custom config path
  ...
jdconrad added a commit that referenced this pull request Oct 23, 2017
)

Adds several small whitelist data structures and a new Whitelist class to separate the idea of loading a whitelist from the actual Painless Definition class. This is the first step of many in allowing users to define custom whitelists per context. Also supports the idea of loading multiple whitelists from different sources for a single context.
@jdconrad jdconrad deleted the whitelist9 branch October 30, 2017 16:44
@clintongormley clintongormley added :Core/Infra/Scripting Scripting abstractions, Painless, and Mustache and removed :Plugin Lang Painless labels Feb 14, 2018
@jimczi jimczi added v7.0.0-beta1 and removed v7.0.0 labels Feb 7, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
:Core/Infra/Scripting Scripting abstractions, Painless, and Mustache >enhancement v6.1.0 v7.0.0-beta1
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants