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