• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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