diff options
Diffstat (limited to 'src/main/javassist/util/proxy/SecurityActions.java')
-rwxr-xr-x | src/main/javassist/util/proxy/SecurityActions.java | 232 |
1 files changed, 191 insertions, 41 deletions
diff --git a/src/main/javassist/util/proxy/SecurityActions.java b/src/main/javassist/util/proxy/SecurityActions.java index ed1ec981..acb89c8d 100755 --- a/src/main/javassist/util/proxy/SecurityActions.java +++ b/src/main/javassist/util/proxy/SecurityActions.java @@ -15,6 +15,8 @@ */ package javassist.util.proxy; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; import java.lang.reflect.AccessibleObject; import java.lang.reflect.Constructor; import java.lang.reflect.Field; @@ -23,46 +25,99 @@ 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; -class SecurityActions { - static Method[] getDeclaredMethods(final Class clazz) { +import javassist.bytecode.ClassFile; + +class SecurityActions extends SecurityManager +{ + public static final SecurityActions stack = new SecurityActions(); + /** + * Since Java 9 abruptly removed <code>Reflection.getCallerClass()</code> + * in favour of <code>StackWalker</code> we are left having to find a + * solution for the older versions without upsetting the new compiler. + * + * The member scoped function <code>getClassContext()</code> + * available as a <code>SecurityManager</code> sibling remains + * functional across all versions, for now. + * + * @return represents the declaring class of the method that invoked + * the method that called this or idx 2 on the stack trace. + * @since 3.23 */ + public Class<?> getCallerClass() + { + return getClassContext()[2]; + } + + + static Method[] getDeclaredMethods(final Class<?> clazz) + { if (System.getSecurityManager() == null) return clazz.getDeclaredMethods(); else { - return (Method[]) AccessController - .doPrivileged(new PrivilegedAction() { - public Object run() { - return clazz.getDeclaredMethods(); - } - }); + return AccessController.doPrivileged( + new PrivilegedAction<Method[]>() { + public Method[] run() { + return clazz.getDeclaredMethods(); + } + }); } } - static Constructor[] getDeclaredConstructors(final Class clazz) { + static Constructor<?>[] getDeclaredConstructors(final Class<?> clazz) + { if (System.getSecurityManager() == null) return clazz.getDeclaredConstructors(); else { - return (Constructor[]) AccessController - .doPrivileged(new PrivilegedAction() { - public Object run() { - return clazz.getDeclaredConstructors(); - } - }); + return AccessController.doPrivileged( + new PrivilegedAction<Constructor<?>[]>() { + public Constructor<?>[] run() { + return clazz.getDeclaredConstructors(); + } + }); } } - static Method getDeclaredMethod(final Class clazz, final String name, - final Class[] types) throws NoSuchMethodException { + static MethodHandle getMethodHandle(final Class<?> clazz, final + String name, final Class<?>[] params) throws NoSuchMethodException + { + try { + return AccessController.doPrivileged( + new PrivilegedExceptionAction<MethodHandle>() { + public MethodHandle run() throws IllegalAccessException, + NoSuchMethodException, SecurityException { + Method rmet = clazz.getDeclaredMethod(name, params); + rmet.setAccessible(true); + MethodHandle meth = MethodHandles.lookup().unreflect(rmet); + rmet.setAccessible(false); + return meth; + } + }); + } + catch (PrivilegedActionException e) { + if (e.getCause() instanceof NoSuchMethodException) + throw (NoSuchMethodException) e.getCause(); + throw new RuntimeException(e.getCause()); + } + } + + static Method getDeclaredMethod(final Class<?> clazz, final String name, + final Class<?>[] types) throws NoSuchMethodException + { if (System.getSecurityManager() == null) return clazz.getDeclaredMethod(name, types); else { try { - return (Method) AccessController - .doPrivileged(new PrivilegedExceptionAction() { - public Object run() throws Exception { - return clazz.getDeclaredMethod(name, types); - } - }); + return AccessController.doPrivileged( + new PrivilegedExceptionAction<Method>() { + public Method run() throws Exception { + return clazz.getDeclaredMethod(name, types); + } + }); } catch (PrivilegedActionException e) { if (e.getCause() instanceof NoSuchMethodException) @@ -73,20 +128,20 @@ class SecurityActions { } } - static Constructor getDeclaredConstructor(final Class clazz, - final Class[] types) + static Constructor<?> getDeclaredConstructor(final Class<?> clazz, + final Class<?>[] types) throws NoSuchMethodException { if (System.getSecurityManager() == null) return clazz.getDeclaredConstructor(types); else { try { - return (Constructor) AccessController - .doPrivileged(new PrivilegedExceptionAction() { - public Object run() throws Exception { - return clazz.getDeclaredConstructor(types); - } - }); + return AccessController.doPrivileged( + new PrivilegedExceptionAction<Constructor<?>>() { + public Constructor<?> run() throws Exception { + return clazz.getDeclaredConstructor(types); + } + }); } catch (PrivilegedActionException e) { if (e.getCause() instanceof NoSuchMethodException) @@ -98,12 +153,13 @@ class SecurityActions { } static void setAccessible(final AccessibleObject ao, - final boolean accessible) { + final boolean accessible) + { if (System.getSecurityManager() == null) ao.setAccessible(accessible); else { - AccessController.doPrivileged(new PrivilegedAction() { - public Object run() { + AccessController.doPrivileged(new PrivilegedAction<Void>() { + public Void run() { ao.setAccessible(accessible); return null; } @@ -118,19 +174,113 @@ class SecurityActions { fld.set(target, value); else { try { - AccessController.doPrivileged(new PrivilegedExceptionAction() { - public Object run() throws Exception { - fld.set(target, value); - return null; - } - }); + AccessController.doPrivileged( + new PrivilegedExceptionAction<Void>() { + public Void run() throws Exception { + fld.set(target, value); + return null; + } + }); } catch (PrivilegedActionException e) { if (e.getCause() instanceof NoSuchMethodException) throw (IllegalAccessException) e.getCause(); - throw new RuntimeException(e.getCause()); } } } + + static TheUnsafe getSunMiscUnsafeAnonymously() throws ClassNotFoundException + { + try { + return AccessController.doPrivileged( + new PrivilegedExceptionAction<TheUnsafe>() { public TheUnsafe run() throws + ClassNotFoundException, NoSuchFieldException, SecurityException, + IllegalArgumentException, IllegalAccessException { + Class<?> unsafe = Class.forName("sun.misc.Unsafe"); + Field theUnsafe = unsafe.getDeclaredField("theUnsafe"); + theUnsafe.setAccessible(true); + TheUnsafe usf = stack.new TheUnsafe(unsafe, theUnsafe.get(null)); + theUnsafe.setAccessible(false); + disableWarning(usf); + return usf; + } + }); + } + catch (PrivilegedActionException e) { + if (e.getCause() instanceof ClassNotFoundException) + throw (ClassNotFoundException) e.getCause(); + if (e.getCause() instanceof NoSuchFieldException) + throw new ClassNotFoundException("No such instance.", e.getCause()); + if (e.getCause() instanceof IllegalAccessException + || e.getCause() instanceof IllegalAccessException + || e.getCause() instanceof SecurityException) + throw new ClassNotFoundException("Security denied access.", e.getCause()); + throw new RuntimeException(e.getCause()); + } + } + /** + * _The_ Notorious sun.misc.Unsafe in all its glory, but anonymous + * so as not to attract unwanted attention. Kept in two separate + * parts it manages to avoid detection from linker/compiler/general + * complainers and those. This functionality will vanish from the + * JDK soon but in the meantime it shouldn't be an obstacle. + * + * All exposed methods are cached in a dictionary with overloaded + * methods collected under their corresponding keys. Currently the + * implementation assumes there is only one, if you need find a + * need there will have to be a compare. + * @since 3.23 */ + class TheUnsafe + { + final Class<?> unsafe; + final Object theUnsafe; + final Map<String, List<Method>> methods = + new HashMap<String, List<Method>>(); + + 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<Method>(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; + } + } + /** + * Java 9 now complains about every privileged action regardless. + * Displaying warnings of "illegal usage" and then instructing users + * to go hassle the maintainers in order to have it fixed. + * Making it hush for now, see all fixed. + * @param tu theUnsafe that'll fix it */ + 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*/ } + } } + |