1 /* 2 * Javassist, a Java-bytecode translator toolkit. 3 * Copyright (C) 1999- Shigeru Chiba. All Rights Reserved. 4 * 5 * The contents of this file are subject to the Mozilla Public License Version 6 * 1.1 (the "License"); you may not use this file except in compliance with 7 * the License. Alternatively, the contents of this file may be used under 8 * the terms of the GNU Lesser General Public License Version 2.1 or later, 9 * or the Apache License Version 2.0. 10 * 11 * Software distributed under the License is distributed on an "AS IS" basis, 12 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 13 * for the specific language governing rights and limitations under the 14 * License. 15 */ 16 package javassist.util.proxy; 17 18 import java.lang.invoke.MethodHandle; 19 import java.lang.invoke.MethodHandles; 20 import java.lang.reflect.AccessibleObject; 21 import java.lang.reflect.Constructor; 22 import java.lang.reflect.Field; 23 import java.lang.reflect.Method; 24 import java.security.AccessController; 25 import java.security.PrivilegedAction; 26 import java.security.PrivilegedActionException; 27 import java.security.PrivilegedExceptionAction; 28 import java.util.ArrayList; 29 import java.util.Collections; 30 import java.util.HashMap; 31 import java.util.List; 32 import java.util.Map; 33 34 import javassist.bytecode.ClassFile; 35 36 class SecurityActions extends SecurityManager 37 { 38 public static final SecurityActions stack = new SecurityActions(); 39 40 /** 41 * Since Java 9 abruptly removed <code>Reflection.getCallerClass()</code> 42 * in favour of <code>StackWalker</code> we are left having to find a 43 * solution for the older versions without upsetting the new compiler. 44 * 45 * The member scoped function <code>getClassContext()</code> 46 * available as a <code>SecurityManager</code> sibling remains 47 * functional across all versions, for now. 48 * 49 * @return represents the declaring class of the method that invoked 50 * the method that called this or index 2 on the stack trace. 51 * @since 3.23 52 */ getCallerClass()53 public Class<?> getCallerClass() { 54 return getClassContext()[2]; 55 } 56 getDeclaredMethods(final Class<?> clazz)57 static Method[] getDeclaredMethods(final Class<?> clazz) 58 { 59 if (System.getSecurityManager() == null) 60 return clazz.getDeclaredMethods(); 61 else { 62 return AccessController.doPrivileged( 63 new PrivilegedAction<Method[]>() { 64 public Method[] run() { 65 return clazz.getDeclaredMethods(); 66 } 67 }); 68 } 69 } 70 71 static Constructor<?>[] getDeclaredConstructors(final Class<?> clazz) 72 { 73 if (System.getSecurityManager() == null) 74 return clazz.getDeclaredConstructors(); 75 else { 76 return AccessController.doPrivileged( 77 new PrivilegedAction<Constructor<?>[]>() { 78 public Constructor<?>[] run() { 79 return clazz.getDeclaredConstructors(); 80 } 81 }); 82 } 83 } 84 85 static MethodHandle getMethodHandle(final Class<?> clazz, final 86 String name, final Class<?>[] params) throws NoSuchMethodException 87 { 88 try { 89 return AccessController.doPrivileged( 90 new PrivilegedExceptionAction<MethodHandle>() { 91 public MethodHandle run() throws IllegalAccessException, 92 NoSuchMethodException, SecurityException { 93 Method rmet = clazz.getDeclaredMethod(name, params); 94 rmet.setAccessible(true); 95 MethodHandle meth = MethodHandles.lookup().unreflect(rmet); 96 rmet.setAccessible(false); 97 return meth; 98 } 99 }); 100 } 101 catch (PrivilegedActionException e) { 102 if (e.getCause() instanceof NoSuchMethodException) 103 throw (NoSuchMethodException) e.getCause(); 104 throw new RuntimeException(e.getCause()); 105 } 106 } 107 108 static Method getDeclaredMethod(final Class<?> clazz, final String name, 109 final Class<?>[] types) throws NoSuchMethodException 110 { 111 if (System.getSecurityManager() == null) 112 return clazz.getDeclaredMethod(name, types); 113 else { 114 try { 115 return AccessController.doPrivileged( 116 new PrivilegedExceptionAction<Method>() { 117 public Method run() throws Exception { 118 return clazz.getDeclaredMethod(name, types); 119 } 120 }); 121 } 122 catch (PrivilegedActionException e) { 123 if (e.getCause() instanceof NoSuchMethodException) 124 throw (NoSuchMethodException) e.getCause(); 125 126 throw new RuntimeException(e.getCause()); 127 } 128 } 129 } 130 131 static Constructor<?> getDeclaredConstructor(final Class<?> clazz, 132 final Class<?>[] types) 133 throws NoSuchMethodException 134 { 135 if (System.getSecurityManager() == null) 136 return clazz.getDeclaredConstructor(types); 137 else { 138 try { 139 return AccessController.doPrivileged( 140 new PrivilegedExceptionAction<Constructor<?>>() { 141 public Constructor<?> run() throws Exception { 142 return clazz.getDeclaredConstructor(types); 143 } 144 }); 145 } 146 catch (PrivilegedActionException e) { 147 if (e.getCause() instanceof NoSuchMethodException) 148 throw (NoSuchMethodException) e.getCause(); 149 150 throw new RuntimeException(e.getCause()); 151 } 152 } 153 } 154 155 static void setAccessible(final AccessibleObject ao, 156 final boolean accessible) 157 { 158 if (System.getSecurityManager() == null) 159 ao.setAccessible(accessible); 160 else { 161 AccessController.doPrivileged(new PrivilegedAction<Void>() { 162 public Void run() { 163 ao.setAccessible(accessible); 164 return null; 165 } 166 }); 167 } 168 } 169 170 static void set(final Field fld, final Object target, final Object value) 171 throws IllegalAccessException 172 { 173 if (System.getSecurityManager() == null) 174 fld.set(target, value); 175 else { 176 try { 177 AccessController.doPrivileged( 178 new PrivilegedExceptionAction<Void>() { 179 public Void run() throws Exception { 180 fld.set(target, value); 181 return null; 182 } 183 }); 184 } 185 catch (PrivilegedActionException e) { 186 if (e.getCause() instanceof NoSuchMethodException) 187 throw (IllegalAccessException) e.getCause(); 188 throw new RuntimeException(e.getCause()); 189 } 190 } 191 } 192 193 static TheUnsafe getSunMiscUnsafeAnonymously() throws ClassNotFoundException 194 { 195 try { 196 return AccessController.doPrivileged( 197 new PrivilegedExceptionAction<TheUnsafe>() { public TheUnsafe run() throws 198 ClassNotFoundException, NoSuchFieldException, SecurityException, 199 IllegalArgumentException, IllegalAccessException { 200 Class<?> unsafe = Class.forName("sun.misc.Unsafe"); 201 Field theUnsafe = unsafe.getDeclaredField("theUnsafe"); 202 theUnsafe.setAccessible(true); 203 TheUnsafe usf = stack.new TheUnsafe(unsafe, theUnsafe.get(null)); 204 theUnsafe.setAccessible(false); 205 disableWarning(usf); 206 return usf; 207 } 208 }); 209 } 210 catch (PrivilegedActionException e) { 211 if (e.getCause() instanceof ClassNotFoundException) 212 throw (ClassNotFoundException) e.getCause(); 213 if (e.getCause() instanceof NoSuchFieldException) 214 throw new ClassNotFoundException("No such instance.", e.getCause()); 215 if (e.getCause() instanceof IllegalAccessException 216 || e.getCause() instanceof IllegalAccessException 217 || e.getCause() instanceof SecurityException) 218 throw new ClassNotFoundException("Security denied access.", e.getCause()); 219 throw new RuntimeException(e.getCause()); 220 } 221 } 222 /** 223 * _The_ Notorious sun.misc.Unsafe in all its glory, but anonymous 224 * so as not to attract unwanted attention. Kept in two separate 225 * parts it manages to avoid detection from linker/compiler/general 226 * complainers and those. This functionality will vanish from the 227 * JDK soon but in the meantime it shouldn't be an obstacle. 228 * 229 * All exposed methods are cached in a dictionary with overloaded 230 * methods collected under their corresponding keys. Currently the 231 * implementation assumes there is only one, if you need find a 232 * need there will have to be a compare. 233 * @since 3.23 */ 234 class TheUnsafe 235 { 236 final Class<?> unsafe; 237 final Object theUnsafe; 238 final Map<String, List<Method>> methods = 239 new HashMap<String, List<Method>>(); 240 241 TheUnsafe(Class<?> c, Object o) 242 { 243 this.unsafe = c; 244 this.theUnsafe = o; 245 for (Method m: unsafe.getDeclaredMethods()) { 246 if (!methods.containsKey(m.getName())) { 247 methods.put(m.getName(), Collections.singletonList(m)); 248 continue; 249 } 250 if (methods.get(m.getName()).size() == 1) 251 methods.put(m.getName(), 252 new ArrayList<Method>(methods.get(m.getName()))); 253 methods.get(m.getName()).add(m); 254 } 255 } 256 257 private Method getM(String name, Object[] o) 258 { 259 return methods.get(name).get(0); 260 } 261 262 public Object call(String name, Object... args) 263 { 264 try { 265 return getM(name, args).invoke(theUnsafe, args); 266 } catch (Throwable t) {t.printStackTrace();} 267 return null; 268 } 269 } 270 /** 271 * Java 9 now complains about every privileged action regardless. 272 * Displaying warnings of "illegal usage" and then instructing users 273 * to go hassle the maintainers in order to have it fixed. 274 * Making it hush for now, see all fixed. 275 * @param tu theUnsafe that'll fix it */ 276 static void disableWarning(TheUnsafe tu) { 277 try { 278 if (ClassFile.MAJOR_VERSION < ClassFile.JAVA_9) 279 return; 280 Class<?> cls = Class.forName("jdk.internal.module.IllegalAccessLogger"); 281 Field logger = cls.getDeclaredField("logger"); 282 tu.call("putObjectVolatile", cls, tu.call("staticFieldOffset", logger), null); 283 } catch (Exception e) { /*swallow*/ } 284 } 285 } 286 287