1 /* 2 * Copyright (c) 2010, 2013, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package jdk.nashorn.api.scripting; 27 28 import static org.testng.Assert.fail; 29 30 import java.lang.reflect.InvocationHandler; 31 import java.lang.reflect.Method; 32 import java.lang.reflect.Proxy; 33 import java.util.Objects; 34 import javax.script.Invocable; 35 import javax.script.ScriptEngine; 36 import javax.script.ScriptEngineManager; 37 import javax.script.ScriptException; 38 import org.testng.annotations.Test; 39 40 /** 41 * jsr223 tests for security access checks. 42 */ 43 public class ScriptEngineSecurityTest { 44 45 private void log(final String msg) { 46 org.testng.Reporter.log(msg, true); 47 } 48 49 @Test 50 public void securityPackagesTest() { 51 if (System.getSecurityManager() == null) { 52 // pass vacuously 53 return; 54 } 55 56 final ScriptEngineManager m = new ScriptEngineManager(); 57 final ScriptEngine e = m.getEngineByName("nashorn"); 58 try { 59 e.eval("var v = Packages.sun.misc.Unsafe;"); 60 fail("should have thrown SecurityException"); 61 } catch (final Exception exp) { 62 if (exp instanceof SecurityException) { 63 log("got " + exp + " as expected"); 64 } else { 65 fail(exp.getMessage()); 66 } 67 } 68 } 69 70 @Test 71 public void securityJavaTypeTest() { 72 if (System.getSecurityManager() == null) { 73 // pass vacuously 74 return; 75 } 76 77 final ScriptEngineManager m = new ScriptEngineManager(); 78 final ScriptEngine e = m.getEngineByName("nashorn"); 79 try { 80 e.eval("var v = Java.type('sun.misc.Unsafe');"); 81 fail("should have thrown SecurityException"); 82 } catch (final Exception exp) { 83 if (exp instanceof SecurityException) { 84 log("got " + exp + " as expected"); 85 } else { 86 fail(exp.getMessage()); 87 } 88 } 89 } 90 91 @Test 92 public void securityClassForNameTest() { 93 if (System.getSecurityManager() == null) { 94 // pass vacuously 95 return; 96 } 97 98 final ScriptEngineManager m = new ScriptEngineManager(); 99 final ScriptEngine e = m.getEngineByName("nashorn"); 100 try { 101 e.eval("var v = java.lang.Class.forName('sun.misc.Unsafe');"); 102 fail("should have thrown SecurityException"); 103 } catch (final Exception exp) { 104 if (exp instanceof SecurityException) { 105 log("got " + exp + " as expected"); 106 } else { 107 fail(exp.getMessage()); 108 } 109 } 110 } 111 112 @Test 113 public void securitySystemExit() { 114 if (System.getSecurityManager() == null) { 115 // pass vacuously 116 return; 117 } 118 119 final ScriptEngineManager m = new ScriptEngineManager(); 120 final ScriptEngine e = m.getEngineByName("nashorn"); 121 try { 122 e.eval("java.lang.System.exit(0);"); 123 fail("should have thrown SecurityException"); 124 } catch (final Exception exp) { 125 if (exp instanceof SecurityException) { 126 log("got " + exp + " as expected"); 127 } else { 128 fail(exp.getMessage()); 129 } 130 } 131 } 132 133 134 @Test 135 public void securitySystemExitFromFinalizerThread() throws ScriptException { 136 if (System.getSecurityManager() == null) { 137 // pass vacuously 138 return; 139 } 140 141 final ScriptEngineManager m = new ScriptEngineManager(); 142 final ScriptEngine e = m.getEngineByName("nashorn"); 143 e.eval("var o = Java.extend(Java.type('javax.imageio.spi.ServiceRegistry'), { deregisterAll: this.exit.bind(null, 1234)});\n" + 144 "new o(new java.util.ArrayList().iterator())"); 145 System.gc(); 146 System.runFinalization(); 147 // NOTE: this test just exits the VM if it fails. 148 } 149 150 @Test 151 public void securitySystemLoadLibrary() { 152 if (System.getSecurityManager() == null) { 153 // pass vacuously 154 return; 155 } 156 157 final ScriptEngineManager m = new ScriptEngineManager(); 158 final ScriptEngine e = m.getEngineByName("nashorn"); 159 try { 160 e.eval("java.lang.System.loadLibrary('foo');"); 161 fail("should have thrown SecurityException"); 162 } catch (final Exception exp) { 163 if (exp instanceof SecurityException) { 164 log("got " + exp + " as expected"); 165 } else { 166 fail(exp.getMessage()); 167 } 168 } 169 } 170 171 @Test 172 /** 173 * Check that script can't implement sensitive package interfaces. 174 */ 175 public void checkSensitiveInterfaceImplTest() throws ScriptException { 176 if (System.getSecurityManager() == null) { 177 // pass vacuously 178 return; 179 } 180 181 final ScriptEngineManager m = new ScriptEngineManager(); 182 final ScriptEngine e = m.getEngineByName("nashorn"); 183 final Object[] holder = new Object[1]; 184 e.put("holder", holder); 185 // put an empty script object into array 186 e.eval("holder[0] = {}"); 187 // holder[0] is an object of some subclass of ScriptObject 188 final Class<?> ScriptObjectClass = holder[0].getClass().getSuperclass(); 189 final Class<?> PropertyAccessClass = ScriptObjectClass.getInterfaces()[0]; 190 // implementation methods for PropertyAccess class 191 e.eval("function set() {}; function get() {}; function getInt(){} " + 192 "function getDouble(){}; function getLong() {}; " + 193 "this.delete = function () {}; function has() {}; " + 194 "function hasOwnProperty() {}"); 195 196 // get implementation of a restricted package interface 197 try { 198 log(Objects.toString(((Invocable)e).getInterface((Class<?>)PropertyAccessClass))); 199 fail("should have thrown SecurityException"); 200 } catch (final Exception exp) { 201 if (! (exp instanceof SecurityException)) { 202 fail("SecurityException expected, got " + exp); 203 } 204 } 205 } 206 207 // @bug 8032948: Nashorn linkages awry 208 public static class FakeProxy extends Proxy { 209 public FakeProxy(final InvocationHandler ih) { 210 super(ih); 211 } 212 213 public static Class<?> makeProxyClass(final ClassLoader cl, final Class<?>... ifaces) { 214 return Proxy.getProxyClass(cl, ifaces); 215 } 216 } 217 218 @Test 219 public void fakeProxySubclassAccessCheckTest() throws ScriptException { 220 if (System.getSecurityManager() == null) { 221 // pass vacuously 222 return; 223 } 224 225 final ScriptEngineManager m = new ScriptEngineManager(); 226 final ScriptEngine e = m.getEngineByName("nashorn"); 227 228 e.put("name", ScriptEngineSecurityTest.class.getName()); 229 e.put("cl", ScriptEngineSecurityTest.class.getClassLoader()); 230 e.put("intfs", new Class[] { Runnable.class }); 231 232 final String getClass = "Java.type(name + '$FakeProxy').getProxyClass(cl, intfs);"; 233 234 // Should not be able to call static methods of Proxy via fake subclass 235 try { 236 final Class<?> c = (Class<?>)e.eval(getClass); 237 fail("should have thrown SecurityException"); 238 } catch (final Exception exp) { 239 if (! (exp instanceof SecurityException)) { 240 fail("SecurityException expected, got " + exp); 241 } 242 } 243 } 244 245 @Test 246 public void fakeProxySubclassAccessCheckTest2() throws ScriptException { 247 if (System.getSecurityManager() == null) { 248 // pass vacuously 249 return; 250 } 251 252 final ScriptEngineManager m = new ScriptEngineManager(); 253 final ScriptEngine e = m.getEngineByName("nashorn"); 254 255 e.put("name", ScriptEngineSecurityTest.class.getName()); 256 e.put("cl", ScriptEngineSecurityTest.class.getClassLoader()); 257 e.put("intfs", new Class[] { Runnable.class }); 258 259 final String getClass = "Java.type(name + '$FakeProxy').makeProxyClass(cl, intfs);"; 260 261 // Should not be able to call static methods of Proxy via fake subclass 262 try { 263 final Class<?> c = (Class<?>)e.eval(getClass); 264 fail("should have thrown SecurityException"); 265 } catch (final Exception exp) { 266 if (! (exp instanceof SecurityException)) { 267 fail("SecurityException expected, got " + exp); 268 } 269 } 270 } 271 272 @Test 273 public static void proxyStaticAccessCheckTest() throws ScriptException { 274 final ScriptEngineManager m = new ScriptEngineManager(); 275 final ScriptEngine e = m.getEngineByName("nashorn"); 276 final Runnable r = (Runnable)Proxy.newProxyInstance( 277 ScriptEngineTest.class.getClassLoader(), 278 new Class[] { Runnable.class }, 279 new InvocationHandler() { 280 @Override 281 public Object invoke(final Object p, final Method m, final Object[] a) { 282 return null; 283 } 284 }); 285 286 e.put("rc", r.getClass()); 287 e.put("cl", ScriptEngineSecurityTest.class.getClassLoader()); 288 e.put("intfs", new Class[] { Runnable.class }); 289 290 // make sure static methods of Proxy is not accessible via subclass 291 try { 292 e.eval("rc.static.getProxyClass(cl, intfs)"); 293 fail("Should have thrown SecurityException"); 294 } catch (final Exception exp) { 295 if (! (exp instanceof SecurityException)) { 296 fail("SecurityException expected, got " + exp); 297 } 298 } 299 } 300 }