1 /* 2 * Copyright (c) 2014, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 package org.graalvm.compiler.jtt.except; 24 25 import org.junit.BeforeClass; 26 import org.junit.Test; 27 28 import org.graalvm.compiler.jtt.JTTTest; 29 import org.graalvm.compiler.test.ExportingClassLoader; 30 31 import jdk.internal.org.objectweb.asm.ClassWriter; 32 import jdk.internal.org.objectweb.asm.MethodVisitor; 33 import jdk.internal.org.objectweb.asm.Opcodes; 34 import jdk.internal.org.objectweb.asm.Type; 35 36 public class UntrustedInterfaces extends JTTTest { 37 38 public interface CallBack { 39 int callBack(TestInterface ti); 40 } 41 42 private interface TestInterface { 43 int method(); 44 } 45 46 /** 47 * What a GoodPill would look like. 48 * 49 * <pre> 50 * private static final class GoodPill extends Pill { 51 * public void setField() { 52 * field = new TestConstant(); 53 * } 54 * 55 * public void setStaticField() { 56 * staticField = new TestConstant(); 57 * } 58 * 59 * public int callMe(CallBack callback) { 60 * return callback.callBack(new TestConstant()); 61 * } 62 * 63 * public TestInterface get() { 64 * return new TestConstant(); 65 * } 66 * } 67 * 68 * private static final class TestConstant implements TestInterface { 69 * public int method() { 70 * return 42; 71 * } 72 * } 73 * </pre> 74 */ 75 public abstract static class Pill { 76 public static TestInterface staticField; 77 public TestInterface field; 78 79 public abstract void setField(); 80 81 public abstract void setStaticField(); 82 83 public abstract int callMe(CallBack callback); 84 85 public abstract TestInterface get(); 86 } 87 88 public int callBack(TestInterface list) { 89 return list.method(); 90 } 91 92 public int staticFieldInvoke(Pill pill) { 93 pill.setStaticField(); 94 return Pill.staticField.method(); 95 } 96 97 public int fieldInvoke(Pill pill) { 98 pill.setField(); 99 return pill.field.method(); 100 } 101 102 public int argumentInvoke(Pill pill) { 103 return pill.callMe(ti -> ti.method()); 104 } 105 106 public int returnInvoke(Pill pill) { 107 return pill.get().method(); 108 } 109 110 @SuppressWarnings("cast") 111 public boolean staticFieldInstanceof(Pill pill) { 112 pill.setStaticField(); 113 return Pill.staticField instanceof TestInterface; 114 } 115 116 @SuppressWarnings("cast") 117 public boolean fieldInstanceof(Pill pill) { 118 pill.setField(); 119 return pill.field instanceof TestInterface; 120 } 121 122 @SuppressWarnings("cast") 123 public int argumentInstanceof(Pill pill) { 124 return pill.callMe(ti -> ti instanceof TestInterface ? 42 : 24); 125 } 126 127 @SuppressWarnings("cast") 128 public boolean returnInstanceof(Pill pill) { 129 return pill.get() instanceof TestInterface; 130 } 131 132 public TestInterface staticFieldCheckcast(Pill pill) { 133 pill.setStaticField(); 134 return TestInterface.class.cast(Pill.staticField); 135 } 136 137 public TestInterface fieldCheckcast(Pill pill) { 138 pill.setField(); 139 return TestInterface.class.cast(pill.field); 140 } 141 142 public int argumentCheckcast(Pill pill) { 143 return pill.callMe(ti -> TestInterface.class.cast(ti).method()); 144 } 145 146 public TestInterface returnCheckcast(Pill pill) { 147 return TestInterface.class.cast(pill.get()); 148 } 149 150 private static Pill poisonPill; 151 152 // Checkstyle: stop 153 @BeforeClass 154 public static void setUp() throws InstantiationException, IllegalAccessException, ClassNotFoundException { 155 poisonPill = (Pill) new PoisonLoader().findClass(PoisonLoader.POISON_IMPL_NAME).newInstance(); 156 } 157 158 // Checkstyle: resume 159 160 @Test 161 public void testStaticField0() { 162 runTest("staticFieldInvoke", poisonPill); 163 } 164 165 @Test 166 public void testStaticField1() { 167 runTest("staticFieldInstanceof", poisonPill); 168 } 169 170 @Test 171 public void testStaticField2() { 172 runTest("staticFieldCheckcast", poisonPill); 173 } 174 175 @Test 176 public void testField0() { 177 runTest("fieldInvoke", poisonPill); 178 } 179 180 @Test 181 public void testField1() { 182 runTest("fieldInstanceof", poisonPill); 183 } 184 185 @Test 186 public void testField2() { 187 runTest("fieldCheckcast", poisonPill); 188 } 189 190 @Test 191 public void testArgument0() { 192 runTest("argumentInvoke", poisonPill); 193 } 194 195 @Test 196 public void testArgument1() { 197 runTest("argumentInstanceof", poisonPill); 198 } 199 200 @Test 201 public void testArgument2() { 202 runTest("argumentCheckcast", poisonPill); 203 } 204 205 @Test 206 public void testReturn0() { 207 runTest("returnInvoke", poisonPill); 208 } 209 210 @Test 211 public void testReturn1() { 212 runTest("returnInstanceof", poisonPill); 213 } 214 215 @Test 216 public void testReturn2() { 217 runTest("returnCheckcast", poisonPill); 218 } 219 220 private static class PoisonLoader extends ExportingClassLoader { 221 public static final String POISON_IMPL_NAME = "org.graalvm.compiler.jtt.except.PoisonPill"; 222 223 @Override 224 protected Class<?> findClass(String name) throws ClassNotFoundException { 225 if (name.equals(POISON_IMPL_NAME)) { 226 ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); 227 228 cw.visit(Opcodes.V1_8, Opcodes.ACC_PUBLIC, POISON_IMPL_NAME.replace('.', '/'), null, Type.getInternalName(Pill.class), null); 229 // constructor 230 MethodVisitor constructor = cw.visitMethod(Opcodes.ACC_PUBLIC, "<init>", "()V", null, null); 231 constructor.visitCode(); 232 constructor.visitVarInsn(Opcodes.ALOAD, 0); 233 constructor.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(Pill.class), "<init>", "()V", false); 234 constructor.visitInsn(Opcodes.RETURN); 235 constructor.visitMaxs(0, 0); 236 constructor.visitEnd(); 237 238 MethodVisitor setList = cw.visitMethod(Opcodes.ACC_PUBLIC, "setField", "()V", null, null); 239 setList.visitCode(); 240 setList.visitVarInsn(Opcodes.ALOAD, 0); 241 setList.visitTypeInsn(Opcodes.NEW, Type.getInternalName(Object.class)); 242 setList.visitInsn(Opcodes.DUP); 243 setList.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(Object.class), "<init>", "()V", false); 244 setList.visitFieldInsn(Opcodes.PUTFIELD, Type.getInternalName(Pill.class), "field", Type.getDescriptor(TestInterface.class)); 245 setList.visitInsn(Opcodes.RETURN); 246 setList.visitMaxs(0, 0); 247 setList.visitEnd(); 248 249 MethodVisitor setStaticList = cw.visitMethod(Opcodes.ACC_PUBLIC, "setStaticField", "()V", null, null); 250 setStaticList.visitCode(); 251 setStaticList.visitTypeInsn(Opcodes.NEW, Type.getInternalName(Object.class)); 252 setStaticList.visitInsn(Opcodes.DUP); 253 setStaticList.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(Object.class), "<init>", "()V", false); 254 setStaticList.visitFieldInsn(Opcodes.PUTSTATIC, Type.getInternalName(Pill.class), "staticField", Type.getDescriptor(TestInterface.class)); 255 setStaticList.visitInsn(Opcodes.RETURN); 256 setStaticList.visitMaxs(0, 0); 257 setStaticList.visitEnd(); 258 259 MethodVisitor callMe = cw.visitMethod(Opcodes.ACC_PUBLIC, "callMe", Type.getMethodDescriptor(Type.INT_TYPE, Type.getType(CallBack.class)), null, null); 260 callMe.visitCode(); 261 callMe.visitVarInsn(Opcodes.ALOAD, 1); 262 callMe.visitTypeInsn(Opcodes.NEW, Type.getInternalName(Object.class)); 263 callMe.visitInsn(Opcodes.DUP); 264 callMe.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(Object.class), "<init>", "()V", false); 265 callMe.visitMethodInsn(Opcodes.INVOKEINTERFACE, Type.getInternalName(CallBack.class), "callBack", Type.getMethodDescriptor(Type.INT_TYPE, Type.getType(TestInterface.class)), true); 266 callMe.visitInsn(Opcodes.IRETURN); 267 callMe.visitMaxs(0, 0); 268 callMe.visitEnd(); 269 270 MethodVisitor getList = cw.visitMethod(Opcodes.ACC_PUBLIC, "get", Type.getMethodDescriptor(Type.getType(TestInterface.class)), null, null); 271 getList.visitCode(); 272 getList.visitTypeInsn(Opcodes.NEW, Type.getInternalName(Object.class)); 273 getList.visitInsn(Opcodes.DUP); 274 getList.visitMethodInsn(Opcodes.INVOKESPECIAL, Type.getInternalName(Object.class), "<init>", "()V", false); 275 getList.visitInsn(Opcodes.ARETURN); 276 getList.visitMaxs(0, 0); 277 getList.visitEnd(); 278 279 cw.visitEnd(); 280 281 byte[] bytes = cw.toByteArray(); 282 return defineClass(name, bytes, 0, bytes.length); 283 } 284 return super.findClass(name); 285 } 286 } 287 }