From 50dd54dc0552960c80aacded54a9ff7fe0f747f6 Mon Sep 17 00:00:00 2001 From: nickl- Date: Fri, 27 Oct 2017 08:10:22 +0200 Subject: [PATCH] Even now Oracle still not happy. Runtime still throws warnings illegal actions even after all that, there's just no logic to it. We can use Unsafe but don't touch setAccessible. O well might as well enjoy Unsafe while we still can. Wrapped the Unsafe and added method cache with varargs method for invoke calls. Can still do a lot with it but it does what it needs to for now. --- .../util/proxy/DefineClassHelper.java | 15 ++--- .../javassist/util/proxy/SecurityActions.java | 61 ++++++++++++++++++- 2 files changed, 64 insertions(+), 12 deletions(-) diff --git a/src/main/javassist/util/proxy/DefineClassHelper.java b/src/main/javassist/util/proxy/DefineClassHelper.java index aebb5acb..3ed261e5 100644 --- a/src/main/javassist/util/proxy/DefineClassHelper.java +++ b/src/main/javassist/util/proxy/DefineClassHelper.java @@ -38,10 +38,10 @@ public class DefineClassHelper JAVA_9 { final class ReferencedUnsafe { - private final Object sunMiscUnsafeTheUnsafe; + private final SecurityActions.TheUnsafe sunMiscUnsafeTheUnsafe; private final MethodHandle defineClass; - ReferencedUnsafe(Object usf, MethodHandle meth) + ReferencedUnsafe(SecurityActions.TheUnsafe usf, MethodHandle meth) { this.sunMiscUnsafeTheUnsafe = usf; this.defineClass = meth; @@ -54,7 +54,7 @@ public class DefineClassHelper throw new IllegalAccessError("Access denied for caller."); try { return (Class) defineClass.invokeWithArguments( - sunMiscUnsafeTheUnsafe, + sunMiscUnsafeTheUnsafe.theUnsafe, name, b, off, len, loader, protectionDomain); } catch (Throwable e) { if (e instanceof RuntimeException) throw (RuntimeException) e; @@ -72,12 +72,9 @@ public class DefineClassHelper && stack.getCallerClass() != this.getClass()) throw new IllegalAccessError("Access denied for caller."); try { - Object usf = SecurityActions.getSunMiscUnsafeAnonymously(); - MethodHandle meth = SecurityActions.getMethodHandle(ClassLoader.class, - "defineClass", new Class[] { - String.class, byte[].class, int.class, int.class, - ProtectionDomain.class - }); + SecurityActions.TheUnsafe usf = SecurityActions.getSunMiscUnsafeAnonymously(); + MethodHandle meth = MethodHandles.lookup() + .unreflect(usf.methods.get("defineClass").get(0)); return new ReferencedUnsafe(usf, meth); } catch (Throwable e) { throw new RuntimeException("cannot initialize", e); diff --git a/src/main/javassist/util/proxy/SecurityActions.java b/src/main/javassist/util/proxy/SecurityActions.java index 4bc10a8a..574073d0 100755 --- a/src/main/javassist/util/proxy/SecurityActions.java +++ b/src/main/javassist/util/proxy/SecurityActions.java @@ -25,6 +25,14 @@ import java.security.AccessController; import java.security.PrivilegedAction; import java.security.PrivilegedActionException; import java.security.PrivilegedExceptionAction; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javassist.bytecode.ClassFile; + class SecurityActions extends SecurityManager { public static final SecurityActions stack = new SecurityActions(); @@ -170,18 +178,19 @@ class SecurityActions extends SecurityManager } } - static Object getSunMiscUnsafeAnonymously() throws ClassNotFoundException + static TheUnsafe getSunMiscUnsafeAnonymously() throws ClassNotFoundException { try { return AccessController.doPrivileged( - new PrivilegedExceptionAction() { public Object run() throws + new PrivilegedExceptionAction() { public TheUnsafe run() throws ClassNotFoundException, NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException { Class unsafe = Class.forName("sun.misc.Unsafe"); Field theUnsafe = unsafe.getDeclaredField("theUnsafe"); theUnsafe.setAccessible(true); - Object usf = theUnsafe.get(null); + TheUnsafe usf = stack.new TheUnsafe(unsafe, theUnsafe.get(null)); theUnsafe.setAccessible(false); + disableWarning(usf); return usf; } }); @@ -198,4 +207,50 @@ class SecurityActions extends SecurityManager throw new RuntimeException(e.getCause()); } } + class TheUnsafe + { + final Class unsafe; + final Object theUnsafe; + final Map> methods = + new HashMap>(); + + TheUnsafe(Class c, Object o) + { + this.unsafe = c; + this.theUnsafe = o; + for (Method m: unsafe.getDeclaredMethods()) { + if (!methods.containsKey(m.getName())) { + methods.put(m.getName(), Collections.singletonList(m)); + continue; + } + if (methods.get(m.getName()).size() == 1) + methods.put(m.getName(), + new ArrayList(methods.get(m.getName()))); + methods.get(m.getName()).add(m); + } + } + + private Method getM(String name, Object[] o) + { + return methods.get(name).get(0); + } + + public Object call(String name, Object... args) + { + try { + return getM(name, args).invoke(theUnsafe, args); + } catch (Throwable t) {t.printStackTrace();} + return null; + } + } + static void disableWarning(TheUnsafe tu) { + try { + if (ClassFile.MAJOR_VERSION < ClassFile.JAVA_9) + return; + Class cls = Class.forName("jdk.internal.module.IllegalAccessLogger"); + Field logger = cls.getDeclaredField("logger"); + tu.call("putObjectVolatile", cls, tu.call("staticFieldOffset", logger), null); + } catch (Exception e) { /*swallow*/ } + } } + -- 2.39.5