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

Peter Firmstone peter.firmstone at zeus.net.au
Fri Jul 23 08:36:05 UTC 2021


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/2b0b3604/attachment.htm>


More information about the security-dev mailing list