You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

TestSecuredPrivileged.java 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. package test.javassist.proxy;
  2. import static org.hamcrest.Matchers.arrayWithSize;
  3. import static org.hamcrest.Matchers.both;
  4. import static org.hamcrest.Matchers.endsWith;
  5. import static org.hamcrest.Matchers.equalTo;
  6. import static org.hamcrest.Matchers.instanceOf;
  7. import static org.hamcrest.Matchers.not;
  8. import static org.hamcrest.Matchers.notNullValue;
  9. import static org.hamcrest.Matchers.startsWith;
  10. import static org.hamcrest.Matchers.stringContainsInOrder;
  11. import static org.junit.Assert.assertThat;
  12. import static org.junit.Assert.assertTrue;
  13. import java.lang.reflect.Constructor;
  14. import java.lang.reflect.Field;
  15. import java.lang.reflect.InvocationTargetException;
  16. import java.lang.reflect.Method;
  17. import java.lang.reflect.Modifier;
  18. import java.security.ProtectionDomain;
  19. import java.util.Arrays;
  20. import org.junit.Rule;
  21. import org.junit.Test;
  22. import org.junit.rules.ExpectedException;
  23. import javassist.ClassPool;
  24. import javassist.CtClass;
  25. import javassist.util.proxy.DefineClassHelper;
  26. public class TestSecuredPrivileged {
  27. public TestSecuredPrivileged() {
  28. }
  29. @Rule
  30. public ExpectedException thrown = ExpectedException.none();
  31. /**
  32. * Test proves that you cannot even access members with
  33. * private static and final modifiers. */
  34. @Test
  35. public void testDefinedHelperPrivilegedFieldVisibility() {
  36. try {
  37. Field privi = DefineClassHelper.class.getDeclaredField("privileged");
  38. assertTrue(Modifier.isStatic(privi.getModifiers()));
  39. thrown.expectCause(instanceOf(IllegalAccessException.class));
  40. thrown.expectMessage(both(stringContainsInOrder(Arrays.asList("cannot access a member")))
  41. .and(stringContainsInOrder(Arrays.asList("with modifiers \"private static final".split("", 1)))));
  42. privi.get(null);
  43. } catch(Throwable t) {
  44. throw new RuntimeException(t);
  45. }
  46. }
  47. /**
  48. * Test proves that the default enum constant is a class and specifically
  49. * auto selected for Java 9. */
  50. @Test
  51. public void testDefinedHelperPrivilegedField() {
  52. try {
  53. Field privi = DefineClassHelper.class.getDeclaredField("privileged");
  54. assertTrue(Modifier.isStatic(privi.getModifiers()));
  55. Constructor<DefineClassHelper> con = DefineClassHelper.class.getDeclaredConstructor();
  56. con.setAccessible(true);
  57. DefineClassHelper inst = con.newInstance();
  58. assertThat(inst, instanceOf(DefineClassHelper.class));
  59. privi.setAccessible(true);
  60. Object p = privi.get(inst);
  61. assertThat(""+p, equalTo("JAVA_9"));
  62. assertThat(p.getClass().getName(), endsWith("SecuredPrivileged$1"));
  63. } catch(Throwable t) {
  64. throw new RuntimeException(t);
  65. }
  66. }
  67. /**
  68. * Test proves that caller class security is enforced and works
  69. * as expected. */
  70. @Test
  71. public void testDefinedHelperPrivilegedFieldMethodAccessDenied() {
  72. try {
  73. Constructor<DefineClassHelper> con = DefineClassHelper.class.getDeclaredConstructor();
  74. con.setAccessible(true);
  75. DefineClassHelper inst = con.newInstance();
  76. Field privi = DefineClassHelper.class.getDeclaredField("privileged");
  77. privi.setAccessible(true);
  78. Object priviInst = privi.get(inst);
  79. Method defineClass = priviInst.getClass().getDeclaredMethod(
  80. "defineClass", new Class[] {
  81. String.class, byte[].class, int.class, int.class,
  82. ClassLoader.class, ProtectionDomain.class
  83. });
  84. assertThat(defineClass, notNullValue());
  85. defineClass.setAccessible(true);
  86. assertThat(defineClass.getName(), equalTo("defineClass"));
  87. assertTrue(defineClass.canAccess(priviInst));
  88. ClassPool cp = ClassPool.getDefault();
  89. CtClass c = cp.makeClass("a.b.C");
  90. byte[] bc = c.toBytecode();
  91. thrown.expectCause(instanceOf(IllegalAccessError.class));
  92. thrown.expectMessage(equalTo("java.lang.IllegalAccessError: Access denied for caller."));
  93. @SuppressWarnings("unused")
  94. Object res = defineClass.invoke(priviInst, new Object[] {
  95. c.getName(), bc, 0, bc.length, new ClassLoader() {},
  96. ClassLoader.class.getProtectionDomain()
  97. });
  98. } catch(InvocationTargetException t) {
  99. throw new RuntimeException(t.getTargetException());
  100. } catch(Throwable t) { throw new RuntimeException(t); }
  101. }
  102. /**
  103. * Test proves that we do have 3 enum constants in the private static
  104. * inner class. */
  105. @Test
  106. public void testDefinedHelperEnumClass() {
  107. try {
  108. Constructor<DefineClassHelper> con = DefineClassHelper.class.getDeclaredConstructor();
  109. con.setAccessible(true);
  110. assertThat(DefineClassHelper.class.getDeclaredClasses(), arrayWithSize(1));
  111. Class<?> secPriv = DefineClassHelper.class.getDeclaredClasses()[0];
  112. assertTrue(secPriv.isEnum());
  113. assertThat(secPriv.getEnumConstants(), arrayWithSize(3));
  114. assertThat(""+secPriv.getEnumConstants()[0], equalTo("JAVA_9"));
  115. assertThat(""+secPriv.getEnumConstants()[1], equalTo("JAVA_7"));
  116. assertThat(""+secPriv.getEnumConstants()[2], equalTo("JAVA_OTHER"));
  117. } catch (Throwable t) {t.printStackTrace();}
  118. }
  119. /**
  120. * Test proves that you cannot modify private static final reference even
  121. * with setAccessible(true). */
  122. @Test
  123. public void testDefinedHelperCannotSetPrivileged() {
  124. try {
  125. Constructor<DefineClassHelper> con = DefineClassHelper.class.getDeclaredConstructor();
  126. con.setAccessible(true);
  127. DefineClassHelper inst = con.newInstance();
  128. Class<?> secPriv = DefineClassHelper.class.getDeclaredClasses()[0];
  129. Object J7 = secPriv.getEnumConstants()[1];
  130. Field privi = DefineClassHelper.class.getDeclaredField("privileged");
  131. privi.setAccessible(true);
  132. thrown.expectCause(instanceOf(IllegalAccessException.class));
  133. thrown.expectMessage(startsWith("java.lang.IllegalAccessException: Can not set static final"));
  134. privi.set(inst, J7);
  135. } catch (Throwable t) {throw new RuntimeException(t);}
  136. }
  137. /**
  138. * Test proves that you can achieve the impossible and modify private
  139. * static final class reference without an instance. Now we can Mock
  140. * test JDK 6 to 8 functionality */
  141. @Test
  142. public void testDefinedHelperSetPrivilegedToJava7() {
  143. try {
  144. Constructor<DefineClassHelper> con = DefineClassHelper.class.getDeclaredConstructor();
  145. con.setAccessible(true);
  146. DefineClassHelper inst = con.newInstance();
  147. Class<?> secPriv = DefineClassHelper.class.getDeclaredClasses()[0];
  148. Object J9 = secPriv.getEnumConstants()[0];
  149. Object J7 = secPriv.getEnumConstants()[1];
  150. Field privi = DefineClassHelper.class.getDeclaredField("privileged");
  151. privi.setAccessible(true);
  152. Object privInst = privi.get(inst);
  153. Field unsf = privInst.getClass().getDeclaredField("sunMiscUnsafe");
  154. unsf.setAccessible(true);
  155. Object refu = unsf.get(privInst);
  156. Field tuf = refu.getClass().getDeclaredField("sunMiscUnsafeTheUnsafe");
  157. tuf.setAccessible(true);
  158. Object tu = tuf.get(refu);
  159. Method tu_call = tu.getClass().getMethod("call", new Class<?>[] {String.class, Object[].class});
  160. tu_call.setAccessible(true);
  161. long offset = (Long) tu_call.invoke(tu, new Object[] {"staticFieldOffset", new Object[] {privi}});
  162. tu_call.invoke(tu, new Object[] {"putObjectVolatile", new Object[] {DefineClassHelper.class, offset, J7}});
  163. Object p = privi.get(inst);
  164. assertThat(""+p, equalTo("JAVA_7"));
  165. assertThat(p.getClass().getName(), endsWith("SecuredPrivileged$2"));
  166. tu_call.invoke(tu, new Object[] {"putObjectVolatile", new Object[] {DefineClassHelper.class, offset, J9}});
  167. } catch (Throwable t) {t.printStackTrace();}
  168. }
  169. /**
  170. * Test proves that Java 7+ MethodHandle defineClass (or DefineClassHelper.toClass)
  171. * works as expected. */
  172. @Test
  173. public void testDefinedHelperJava7ToClass() {
  174. try {
  175. Constructor<DefineClassHelper> con = DefineClassHelper.class.getDeclaredConstructor();
  176. con.setAccessible(true);
  177. DefineClassHelper inst = con.newInstance();
  178. Class<?> secPriv = DefineClassHelper.class.getDeclaredClasses()[0];
  179. Object J9 = secPriv.getEnumConstants()[0];
  180. Object J7 = secPriv.getEnumConstants()[1];
  181. Field privi = DefineClassHelper.class.getDeclaredField("privileged");
  182. privi.setAccessible(true);
  183. Object privInst = privi.get(inst);
  184. Field unsf = privInst.getClass().getDeclaredField("sunMiscUnsafe");
  185. unsf.setAccessible(true);
  186. Object refu = unsf.get(privInst);
  187. Field tuf = refu.getClass().getDeclaredField("sunMiscUnsafeTheUnsafe");
  188. tuf.setAccessible(true);
  189. Object tu = tuf.get(refu);
  190. Method tu_call = tu.getClass().getMethod("call", new Class<?>[] {String.class, Object[].class});
  191. tu_call.setAccessible(true);
  192. long offset = (Long) tu_call.invoke(tu, new Object[] {"staticFieldOffset", new Object[] {privi}});
  193. tu_call.invoke(tu, new Object[] {"putObjectVolatile", new Object[] {DefineClassHelper.class, offset, J7}});
  194. ClassPool cp = ClassPool.getDefault();
  195. CtClass c = cp.makeClass("a.b.J7");
  196. byte[] bc = c.toBytecode();
  197. Class<?> bcCls = DefineClassHelper.toClass("a.b.J7", new ClassLoader() {}, null, bc);
  198. assertThat(bcCls.getName(), equalTo("a.b.J7"));
  199. assertThat(bcCls.getDeclaredConstructor().newInstance(),
  200. not(equalTo(bcCls.getDeclaredConstructor().newInstance())));
  201. tu_call.invoke(tu, new Object[] {"putObjectVolatile", new Object[] {DefineClassHelper.class, offset, J9}});
  202. } catch (Throwable t) {t.printStackTrace();}
  203. }
  204. /**
  205. * Test proves that Java 6 reflection method defineClass (or DefineClassHelper.toClass)
  206. * works as expected. */
  207. @Test
  208. public void testDefinedHelperJavaOtherToClass() {
  209. try {
  210. Constructor<DefineClassHelper> con = DefineClassHelper.class.getDeclaredConstructor();
  211. con.setAccessible(true);
  212. DefineClassHelper inst = con.newInstance();
  213. Class<?> secPriv = DefineClassHelper.class.getDeclaredClasses()[0];
  214. Object J9 = secPriv.getEnumConstants()[0];
  215. Object JO = secPriv.getEnumConstants()[2];
  216. Field privi = DefineClassHelper.class.getDeclaredField("privileged");
  217. privi.setAccessible(true);
  218. Object privInst = privi.get(inst);
  219. Field unsf = privInst.getClass().getDeclaredField("sunMiscUnsafe");
  220. unsf.setAccessible(true);
  221. Object refu = unsf.get(privInst);
  222. Field tuf = refu.getClass().getDeclaredField("sunMiscUnsafeTheUnsafe");
  223. tuf.setAccessible(true);
  224. Object tu = tuf.get(refu);
  225. Method tu_call = tu.getClass().getMethod("call", new Class<?>[] {String.class, Object[].class});
  226. tu_call.setAccessible(true);
  227. long offset = (Long) tu_call.invoke(tu, new Object[] {"staticFieldOffset", new Object[] {privi}});
  228. tu_call.invoke(tu, new Object[] {"putObjectVolatile", new Object[] {DefineClassHelper.class, offset, JO}});
  229. ClassPool cp = ClassPool.getDefault();
  230. CtClass c = cp.makeClass("a.b.JO");
  231. byte[] bc = c.toBytecode();
  232. Class<?> bcCls = DefineClassHelper.toClass("a.b.JO", new ClassLoader() {}, null, bc);
  233. assertThat(bcCls.getName(), equalTo("a.b.JO"));
  234. assertThat(bcCls.getDeclaredConstructor().newInstance(),
  235. not(equalTo(bcCls.getDeclaredConstructor().newInstance())));
  236. tu_call.invoke(tu, new Object[] {"putObjectVolatile", new Object[] {DefineClassHelper.class, offset, J9}});
  237. } catch (Throwable t) {t.printStackTrace();}
  238. }
  239. /**
  240. * Test proves that default Java 9 defineClass (or DefineClassHelper.toClass)
  241. * works as expected. */
  242. @Test
  243. public void testDefinedHelperDefaultToClass() {
  244. try {
  245. ClassPool cp = ClassPool.getDefault();
  246. CtClass c = cp.makeClass("a.b.D");
  247. byte[] bc = c.toBytecode();
  248. Class<?> bcCls = DefineClassHelper.toClass("a.b.D", new ClassLoader() {}, null, bc);
  249. assertThat(bcCls.getName(), equalTo("a.b.D"));
  250. assertThat(bcCls.getDeclaredConstructor().newInstance(),
  251. not(equalTo(bcCls.getDeclaredConstructor().newInstance())));
  252. } catch (Throwable t) {t.printStackTrace();}
  253. }
  254. }