-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Prevent CachedField and CachedMethod from leaking access permissions … #532
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
Conversation
| private static final ReflectPermission REFLECT_PERMISSION = new ReflectPermission("suppressAccessChecks"); | ||
|
|
||
| static private void checkAccessPermission(Class<?> declaringClass, final int modifiers, boolean isAccessible) { | ||
| final SecurityManager securityManager = System.getSecurityManager(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be good to exit early if securityManager == null, then wont have to check again below.
Also, be good to change order to be private static void ....
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Signature changed. The check is performed only if (securityManager != null && isAccessible)
| return declaringClass.getName().startsWith("java."); | ||
| } | ||
|
|
||
| static public void checkAccessPermission(Method method) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
public isn't needed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
| ); | ||
| } | ||
|
|
||
| public static void checkAccessPermission(Field field) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
public isn't needed
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
| try { | ||
| AccessPermissionChecker.checkAccessPermission(field); | ||
| } | ||
| catch (AccessControlException ex) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason for using IllegalArgumentException? I think the following may be more appropriate:
throw new GroovyRuntimeException("Illegal access to field " + field.getName() + ".", ex);There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To use GroovyRuntimeException we need to patch also MetaClassImpl.getProperty . It was not possible with byte buddy, but as a groovy patch it is possible. I shall do it in a separate commit.
| AccessPermissionChecker.checkAccessPermission(field); | ||
| } | ||
| catch (AccessControlException ex) { | ||
| throw new IllegalArgumentException("Illegal access to field" + " " + field.getName()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
see above comment about GroovyRuntimeException
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As above
| try { | ||
| AccessPermissionChecker.checkAccessPermission(cachedMethod); | ||
| } | ||
| catch (AccessControlException ex) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Throwing an IllegalArgumentException could be confusing since it's not the arguments passed to the invoked method causing the problem. Maybe
throw new InvokerInvocationException(ex)
or
throw new InvokerInvocationException(
new AccessControlException("Illegal access to method" + cachedMethod.getName(), ex)
)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As above
| AccessPermissionChecker.checkAccessPermission(cachedMethod); | ||
| } | ||
| catch (AccessControlException ex) { | ||
| throw new IllegalArgumentException("Illegal access to method" + cachedMethod.getName()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No arguments to this method so IllegalArgumentException doesn't seem right. Think it might be good to either just remove the try/catch or wrap in a GroovyRuntimeException (to capture cachedMethod.getName).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As above
| AccessPermissionChecker.checkAccessPermission(cachedMethod); | ||
| } | ||
| catch (AccessControlException ex) { | ||
| throw new IllegalArgumentException("Illegal access to method" + cachedMethod.getName()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
see comment on setAccessible
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As above
|
|
||
| import groovy.lang.GroovyObject; | ||
|
|
||
| class AccessPermissionChecker { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Might be good to add a private constructor to signal that no instances of this method are desired, since it only contains static methods.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done
|
Changes suggested in the review are implemented. |
| mp = null; | ||
| } catch (GroovyRuntimeException e) { | ||
| // can't access the field directly but there may be a getter | ||
| mp = null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand why this was added. Was there a test that failed because of the other changes that required this. I would have assumed an AccessControlException from CachedField.getProperty would be treated similar to the IllegalAccessException in the same method.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do not have unit test to explain this catch block. I do have the integration test https://issues.apache.org/jira/browse/GROOVY-8163?focusedCommentId=16009695&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-16009695. The problem is that for some classes C with private member called "name" class property C.class.name which corresponds to java calls C.class.getName() does not work unless this catch block is added.
| } catch (IllegalArgumentException e) { | ||
| // can't access the field directly but there may be a getter | ||
| mp = null; | ||
| } catch (GroovyRuntimeException e) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At this point mp should be a CachedField. Since AccessPermissionChecker.checkAccessPermission(field); may now throw a GroovyRuntimeException, we have here the requirement to catch it. Problem is, that mp might not be a CachedField. If we will call a user method here instead, this would lead to a wrong flow. Thus I think the GroovyRuntimeException usage is a bad idea. Better make a new Exception, that extends GroovyRuntimeException and throw that in AccessPermissionChecker, which we then can catch
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think AccessPermissionChecker should only throw exceptions extending from AccessControlException. because it specifically checks access permissions.
So I suggest to introduce public class CacheAccessControlException extends AccessControlException
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On the other side if it does not work because AccessControlExceptions are not handled by the calling code properly public class CacheAccessControlException extends GroovyRuntimeException could also be taken as a hack.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
How do you see it?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
| catch (AccessControlException ex) { | ||
| throw new InvokerInvocationException(new GroovyRuntimeException("Illegal access to method" + cachedMethod.getName())); | ||
| } | ||
| try { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can we move thos try-catch into checkAccessPermission ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that InvokerInvocationException is specific to call of invoke() and it should be not thrown by AccessPermissionChecker directly.
|
Could you please review the changes I implemented on your behalf? |
|
+1 |
|
@dpolivaev can you squash up the commits and change the tabs in @blackdrag I would guess this is a candidate for 2_5_X and above, but maybe too much of a change for 2.4.12, though maybe not |
|
agreed |
|
Done |
|
Thanks. |
…to scripts
https://issues.apache.org/jira/browse/GROOVY-8163