-
-
Notifications
You must be signed in to change notification settings - Fork 3.7k
HHH-12542 - Add necessary privileged action blocks for SM on WildFly #2419
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
@Naros my issue is more with https://hibernate.atlassian.net/browse/HHH-12614 and the original forum post https://discourse.hibernate.org/t/securityexception-with-bytebuddy-and-signed-application-jars/816 . The original error was:
So if I understand that correctly, it means that we cannot generate classes in a package if the protection domain is not consistent with the other classes of the package, which is why I chose to use the protection domain of the original class. As for the If we want to use the protection domain of an Hibernate class, I suspect we will have to generate the proxies in an Hibernate package. What's the issue you have exactly when keeping the protection domain of the original class? |
@gsmet The error I ran into was this
After talking with @dmlloyd he suggested we had a couple options; however, first we needed to ensure that the bytebuddy generated class has a protection domain which is equal to the generating code (Hibernate) rather than the target code. Presently what was happening is exactly the opposite, we were using the target code's protection domain rather than ORM's. After that we had two options:
I found that by making sure that the generated class had the same protection domain as ORM that we did not need any further handling from what I saw. I'm fine taking a different path if someone has any ideas or suggestions. |
It might well be the case as I'm not well versed in this subject but I'm not sure it's doable. As mentioned, in the case of a signed jar, we need the protection domain to be consistent with the one of the other classes of the package. So if we generate the proxy in the same package as the entity, we need it to have the same protection domain. I don't know if it's feasible to generate the proxies in a different package, an Hibernate one, not sure if we need access to protected methods. |
So given the constraints of having the protection domain consistent with the package to support signed jars, we have 2 solutions:
The last solution is to explicitly not support signed jars. |
The case against using the PD of the entity is simply that the user may not wish to grant it reflection permission. If you're okay with that though, then it's probably fine. TBH I think the "best" solution is probably option 3 above: do not use getDeclaredMethod inside the generated class, and instead pass it in or provide a way for the generated class to acquire it securely. |
Two ways to pass things in to a class initializer:
|
This is what the ByteBuddy proxy looks like: public class ProxyTest$SimpleEntity$HibernateProxy$7tVpOdgl
implements ProxyConfiguration {
private ProxyConfiguration.Interceptor $$_hibernate_interceptor;
private static final /* synthetic */ Method cachedValue$7i1hAKhy$4cscpe1;
private static final /* synthetic */ Method cachedValue$7i1hAKhy$5j4bem0;
private static final /* synthetic */ Method cachedValue$7i1hAKhy$7m9oaq0;
private static final /* synthetic */ Method cachedValue$7i1hAKhy$9pqdof1;
public boolean equals(Object object) {
return (Boolean)ProxyConfiguration.InterceptorDispatcher.intercept((Object)this, (Method)cachedValue$7i1hAKhy$5j4bem0, (Object[])new Object[]{object}, (Object)false, (ProxyConfiguration.Interceptor)this.$$_hibernate_interceptor);
}
public String toString() {
return (String)ProxyConfiguration.InterceptorDispatcher.intercept((Object)this, (Method)cachedValue$7i1hAKhy$4cscpe1, (Object[])new Object[0], (Object)null, (ProxyConfiguration.Interceptor)this.$$_hibernate_interceptor);
}
public int hashCode() {
return (Integer)ProxyConfiguration.InterceptorDispatcher.intercept((Object)this, (Method)cachedValue$7i1hAKhy$9pqdof1, (Object[])new Object[0], (Object)0, (ProxyConfiguration.Interceptor)this.$$_hibernate_interceptor);
}
protected Object clone() throws CloneNotSupportedException {
return ProxyConfiguration.InterceptorDispatcher.intercept((Object)this, (Method)cachedValue$7i1hAKhy$7m9oaq0, (Object[])new Object[0], (Object)null, (ProxyConfiguration.Interceptor)this.$$_hibernate_interceptor);
}
public void $$_hibernate_set_interceptor(ProxyConfiguration.Interceptor interceptor) {
this.$$_hibernate_interceptor = interceptor;
}
static {
cachedValue$7i1hAKhy$4cscpe1 = Object.class.getDeclaredMethod("toString", new Class[0]);
cachedValue$7i1hAKhy$5j4bem0 = Object.class.getDeclaredMethod("equals", Object.class);
cachedValue$7i1hAKhy$7m9oaq0 = Object.class.getDeclaredMethod("clone", new Class[0]);
cachedValue$7i1hAKhy$9pqdof1 = Object.class.getDeclaredMethod("hashCode", new Class[0]);
}
} Javassist has the exact same pattern except it runs them as privileged action if the SM is enabled. I don't know exactly which protection domain is used by Javassist though. We should probably ask Rafael to protect these calls with privileged actions. And that lets us with deciding which is better:
|
Is it always just those four methods? Because those could/should easily be cached somewhere. In fact looking them up every time kind of stinks, really. More memory footprint, more CPU consumption on class init. |
Nope, all the proxied entity methods will be there. |
@dmlloyd FWIW, I created raphw/byte-buddy#493 . What I would recommend:
Then we can start the discussion of how we will support the SM in WF 14. |
…r used on WildFly.
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 added 2 comments and I have one big issue with it: usually, we try to check if the security manager is enabled before doing a privileged access.
Typically, you have a good example here: https://github.com/hibernate/hibernate-orm/blob/master/hibernate-core/src/main/java/org/hibernate/jpa/internal/util/PersistenceUtilHelper.java#L380 .
I think we should stick to this pattern.
revInfoCfgResult.getRevisionInfoXmlMapping(), | ||
revInfoCfgResult.getRevisionInfoRelationMapping() | ||
); | ||
this.entitiesConfigurations = AccessController.doPrivileged( new PrivilegedAction<EntitiesConfigurations>() { |
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.
Couldn't this call be more fine grained? It sounds weird we need to run all the configure code in a privileged block?
} | ||
final Callback[] callbacks = resolveEntityCallbacks( entityXClass, callbackType, reflectionManager ); | ||
|
||
final Callback[] callbacks = AccessController.doPrivileged( new PrivilegedAction<Callback[]>() { |
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.
Not sure about the granularity of this call.
Squashed and merged, thanks! |
https://hibernate.atlassian.net/browse/HHH-12542
@gsmet @raphw - Would you guys be able to check my changes to the ByteBuddy implementation to see if that makes sense for the signed jar issue that you guys worked on as a part of HHH-12618? We need to make sure that the proxy we create uses the ORM protection domain and not the target class so that when reflective methods are invoked, the proper access controls are allowed.
@gbadner You may want to compare this with your PR #2280 if you need it backported to 5.1.