]> source.dussan.org Git - javassist.git/commitdiff
Refactored SecActs methods and retain 1.6 source.
authornickl- <github@jigsoft.co.za>
Fri, 27 Oct 2017 05:19:22 +0000 (07:19 +0200)
committernickl- <github@jigsoft.co.za>
Sun, 12 Nov 2017 21:49:21 +0000 (23:49 +0200)
Remembered that 1.6 won't know about MethodHandles so must use reflection methods for them still.

src/main/javassist/util/proxy/DefineClassHelper.java

index 5599316eb3aaef3a9a1f0d5cd8748c1359d57730..ee565d8054b6360e3e8a379a8898df02ebfd2349 100644 (file)
 
 package javassist.util.proxy;
 
-import java.lang.reflect.Method;
-import java.lang.reflect.Field;
-import java.security.ProtectionDomain;
 import java.lang.invoke.MethodHandle;
 import java.lang.invoke.MethodHandles;
 import java.lang.invoke.MethodHandles.Lookup;
-import sun.misc.Unsafe;
-import java.security.AccessController;
-import java.security.PrivilegedAction;
+import java.lang.reflect.Method;
+import java.security.ProtectionDomain;
 
 import javassist.CannotCompileException;
 import javassist.bytecode.ClassFile;
@@ -34,68 +30,100 @@ import javassist.bytecode.ClassFile;
  *
  * @since 3.22
  */
-public class DefineClassHelper {
-    private static enum SecuredPrivileged {
+public class DefineClassHelper
+{
+
+    private static enum SecuredPrivileged
+    {
         JAVA_9 {
-            final class SecuredUnsafe {
-                private final sun.misc.Unsafe theUnsafe;
+            final class ReferencedUnsafe
+            {
+                private final Object sunMiscUnsafeTheUnsafe;
+                private final MethodHandle defineClass;
 
-                SecuredUnsafe(sun.misc.Unsafe usf) {
-                    this.theUnsafe = usf;
+                ReferencedUnsafe(Object usf, MethodHandle meth)
+                {
+                    this.sunMiscUnsafeTheUnsafe = usf;
+                    this.defineClass = meth;
                 }
 
-                @SuppressWarnings("deprecation")
                 Class<?> defineClass(String name, byte[] b, int off, int len,
-                        ClassLoader loader, ProtectionDomain protectionDomain) {
-                    return theUnsafe.defineClass(name, b, off, len, loader, protectionDomain);
+                        ClassLoader loader, ProtectionDomain protectionDomain)
+                                throws ClassFormatError {
+                    if (stack.getCallerClass() != SecuredPrivileged.JAVA_9.getClass())
+                        throw new IllegalAccessError("Access denied for caller.");
+                    try {
+                        return (Class<?>) defineClass.invokeWithArguments(
+                                sunMiscUnsafeTheUnsafe,
+                                name, b, off, len, loader, protectionDomain);
+                    } catch (Throwable e) {
+                        if (e instanceof RuntimeException) throw (RuntimeException) e;
+                        if (e instanceof ClassFormatError) throw (ClassFormatError) e;
+                        throw new ClassFormatError(e.getMessage());
+                    }
+                }
+            }
+            private final ReferencedUnsafe sunMiscUnsafe = getReferencedUnsafe();
+            private final ReferencedUnsafe getReferencedUnsafe()
+            {
+                try {
+                    Object usf = SecurityActions.getSunMiscUnsafeAnonymously();
+                    MethodHandle meth = SecurityActions.getMethodHandle(ClassLoader.class, 
+                            "defineClass", new Class[] {
+                                    String.class, byte[].class, int.class, int.class,
+                                    ProtectionDomain.class
+                                });
+                    return new ReferencedUnsafe(usf, meth);
+                } catch (Throwable e) {
+                    throw new RuntimeException("cannot initialize", e);
                 }
             }
-
-            private final SecuredUnsafe sunMiscUnsafe = AccessController.doPrivileged(
-                    new PrivilegedAction<SecuredUnsafe>() { public SecuredUnsafe run() {
-                        try {
-                            Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
-                            theUnsafe.setAccessible(true);
-                            sun.misc.Unsafe usf = (sun.misc.Unsafe)theUnsafe.get(null);
-                            return new SecuredUnsafe(usf);
-                        }
-                        catch (Throwable t) {}
-                        return null;
-                    }
-                });
 
             @Override
             public Class<?> defineClass(String name, byte[] b, int off, int len,
-                    ClassLoader loader, ProtectionDomain protectionDomain) throws ClassFormatError {
-                return sunMiscUnsafe.defineClass(name, b, off, len, loader, protectionDomain);
+                    ClassLoader loader, ProtectionDomain protectionDomain)
+                            throws ClassFormatError
+            {
+                if (stack.getCallerClass() != DefineClassHelper.class)
+                    throw new IllegalAccessError("Access denied for caller.");
+                return sunMiscUnsafe.defineClass(name, b, off, len, loader,
+                        protectionDomain);
+            }
+        },
             }
         },
         JAVA_OTHER {
-            private final MethodHandle defineClass = AccessController.doPrivileged(
-                    new PrivilegedAction<MethodHandle>() { public MethodHandle run() {
-                    try {
-                        Method rmet = ClassLoader.class.getDeclaredMethod("defineClass", new Class[] {
+            private final Method defineClass = getDefineClassMethod();
+            private final Method getDefineClassMethod() {
+                try {
+                    return SecurityActions.getDeclaredMethod(ClassLoader.class,
+                        "defineClass", new Class[] {
                                 String.class, byte[].class, int.class, int.class, ProtectionDomain.class
                         });
-                        rmet.setAccessible(true);
-                        MethodHandle meth = MethodHandles.lookup().unreflect(rmet);
-                        rmet.setAccessible(false);
-                        return meth;
-                    } catch (Throwable t) {};
-                    return null;
+                } catch (NoSuchMethodException e) {
+                    throw new RuntimeException("cannot initialize", e);
                 }
-            });
+            }
 
             @Override
-            public Class<?> defineClass(String name, byte[] b, int off, int len,
-                    ClassLoader loader, ProtectionDomain protectionDomain) throws ClassFormatError {
+            protected Class<?> defineClass(String name, byte[] b, int off, int len,
+                    ClassLoader loader, ProtectionDomain protectionDomain) throws ClassFormatError
+            {
+                if (stack.getCallerClass() != DefineClassHelper.class)
+                    throw new IllegalAccessError("Access denied for caller.");
                 try {
-                    return (Class<?>) defineClass.invokeWithArguments(loader, name, b, off, len, protectionDomain);
+                    SecurityActions.setAccessible(defineClass, true);
+                    return (Class<?>) defineClass.invoke(loader, new Object[] {
+                            name, b, off, len, protectionDomain
+                        });
                 } catch (Throwable e) {
                     if (e instanceof ClassFormatError) throw (ClassFormatError) e;
                     if (e instanceof RuntimeException) throw (RuntimeException) e;
+                    throw new ClassFormatError(e.getMessage());
+                }
+                finally {
+                    SecurityActions.setAccessible(defineClass, false);
                 }
-                return null;
             }
         };