JEP 411 Headaches: Instrumenting private methods in the JDK for authorization checkpoints.

Peter Firmstone peter.firmstone at zeus.net.au
Fri Jul 23 10:48:35 UTC 2021


Perhaps the solution is to replace the entire class, instead of 
instrumenting one method?

Compile a patched copy of the JVM, with modified class files, then 
replace the existing classes in the JVM with the modified classes?

Kinda like maintaining a fork, but using Agents to instrument the 
original JVM with classes from the fork?

I sure wish there was a better option, if anyone knows one, I'm all ears.

Regards,

Peter.

On 23/07/2021 6:36 pm, Peter Firmstone wrote:
> Post JEP 411, we need to write Agents to replace the current 
> permission checks performed within the JVM by instrumenting it, 
> following advice by OpenJDK developers, however for us this goes 
> against all our previous development practices, no part of our 
> codebase accesses any JDK implementation classes or internal api's.  
> We also don't release anything that depends on deprecated API's.  
> Modules didn't break our code, neither has tightening rules around 
> access in JEP 403.
>
> We have been advised that we need to instrument the JDK with Agent's 
> by OpenJDK.
>
> I am now ready to write these Agents, so that I can begin testing my 
> new authorization layer for Java: 
> https://github.com/pfirmstone/HighPerformanceSecurity
>
> As an example, we need to instrument java.lang.ClassLoader, in this 
> case we need to instrument the following method:
>
> private static Void checkCreateClassLoader(String name);   This check 
> must be performed prior to calling java.lang.Object's constructor, to 
> throw an exception, without making ClassLoader susceptible to a 
> finalizer attack.
>
> Accessing private internal methods goes against all our current 
> development practices, these are at risk of breaking in future.
>
> We cannot add methods with Agent's only change method contents.
>
> I am requesting hooks, in the form of an annotation, such as the 
> following, so that OpenJDK developers know that this method will be 
> instrumented by Agent's and not to change it's signature.
>
> @Instrumented
>
> private static Void checkCreateClassLoader(String name);
>
> If OpenJDK will provide instrumentation hooks, then this is a workable 
> solution for us.
>
> Or is OpenJDK encouraging us to start accessing private methods and 
> have to test each Java release for breakages?
>
> I'm wondering what the point of JEP 403 is if, our solution to JEP 
> 411, is to start instrumenting private methods?   I don't think this 
> is what OpenJDK developers are proposing.
>
> Currently removing SM will allow an attacker to cause our software 
> running on the JVM to parse untrusted data, which previously required 
> an authenticated client?  Permission is only granted to Principal's, 
> of course post JEP 411, these checks will stop working in future, 
> making our software vulnerable to attacks by unauthenticated users.
>
> We're still up in the air about how to provide credentials for our TLS 
> and Kerberos connections, for authentication, I've created support for 
> obtaining the Subject from the Authorization context, in my 
> authorization layer software (linked above), but instrumenting private 
> methods in the JDK goes against all previously learned best practices.
>
> -- 
> Regards,
>   
> Peter Firmstone
>
> Code snippet from java.lang.ClassLoader:
>
> if (name != null && name.isEmpty()) {
>
> throw new IllegalArgumentException("name must be non-empty or null");
>
> }
>
>
> @SuppressWarnings("removal")
>
> SecurityManager security = System.getSecurityManager();
>
> if (security != null) {
>
> security.checkCreateClassLoader();
>
> }
>
> return null;
>
> }
>
>
> private ClassLoader(Void unused, String name, ClassLoader parent) {
>
> this.name = name;
>
> this.parent = parent;
>
> this.unnamedModule = new Module(this);
>
> if (ParallelLoaders.isRegistered(this.getClass())) {
>
> parallelLockMap = new ConcurrentHashMap<>();
>
> assertionLock = new Object();
>
> } else {
>
> // no finer-grained lock; lock on the classloader instance
>
> parallelLockMap = null;
>
> assertionLock = this;
>
> }
>
> this.package2certs = new ConcurrentHashMap<>();
>
> this.nameAndId = nameAndId(this);
>
> }
>
>
> /**
>
> * If the defining loader has a name explicitly set then
>
> * '<loader-name>' @<id>
>
> * If the defining loader has no name then
>
> * <qualified-class-name> @<id>
>
> * If it's built-in loader then omit `@<id>` as there is only one 
> instance.
>
> */
>
> private static String nameAndId(ClassLoader ld) {
>
> String nid = ld.getName() != null ? "\'" + ld.getName() + "\'"
>
> : ld.getClass().getName();
>
> if (!(ld instanceof BuiltinClassLoader)) {
>
> String id = Integer.toHexString(System.identityHashCode(ld));
>
> nid = nid + " @" + id;
>
> }
>
> return nid;
>
> }
>
>
> /**
>
> * Creates a new class loader of the specified name and using the
>
> * specified parent class loader for delegation.
>
> *
>
> * @apiNote If the parent is specified as {@codenull} (for the
>
> * bootstrap class loader) then there is no guarantee that all platform
>
> * classes are visible.
>
> *
>
> * @param name class loader name; or {@codenull} if not named
>
> * @param parent the parent class loader
>
> *
>
> * @throws IllegalArgumentException if the given name is empty.
>
> *
>
> * @throws SecurityException
>
> * If a security manager exists and its
>
> * {@link SecurityManager#checkCreateClassLoader()}
>
> * method doesn't allow creation of a new class loader.
>
> *
>
> * @since 9
>
> */
>
> protected ClassLoader(String name, ClassLoader parent) {
>
> this(checkCreateClassLoader(name), name, parent);
>
> }
> private static Void checkCreateClassLoader(String name) {
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/security-dev/attachments/20210723/d268ff48/attachment.htm>


More information about the security-dev mailing list