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 if (System.getSecurityManager() == null) { 275 // pass vacuously 276 return; 277 } 278 279 final ScriptEngineManager m = new ScriptEngineManager(); 280 final ScriptEngine e = m.getEngineByName("nashorn"); 281 final Runnable r = (Runnable)Proxy.newProxyInstance( 282 ScriptEngineTest.class.getClassLoader(), 283 new Class[] { Runnable.class }, 284 new InvocationHandler() { 285 @Override 286 public Object invoke(final Object p, final Method m, final Object[] a) { 287 return null; 288 } 289 }); 290 291 e.put("rc", r.getClass()); 292 e.put("cl", ScriptEngineSecurityTest.class.getClassLoader()); 293 e.put("intfs", new Class[] { Runnable.class }); 294 295 // make sure static methods of Proxy is not accessible via subclass 296 try { 297 e.eval("rc.static.getProxyClass(cl, intfs)"); 298 fail("Should have thrown SecurityException"); 299 } catch (final Exception exp) { 300 if (! (exp instanceof SecurityException)) { 301 fail("SecurityException expected, got " + exp); 302 } 303 } 304 } 305 306 307 @Test 308 public void nashornConfigSecurityTest() { 309 if (System.getSecurityManager() == null) { 310 // pass vacuously 311 return; 312 } 313 314 final NashornScriptEngineFactory fac = new NashornScriptEngineFactory(); 315 try { 316 fac.getScriptEngine(new ClassFilter() { 317 @Override 318 public boolean exposeToScripts(final String name) { 319 return true; 320 } 321 }); 322 fail("SecurityException should have been thrown"); 323 } catch (final SecurityException exp) {} 324 } 325 326 @Test 327 public void nashornConfigSecurityTest2() { 328 if (System.getSecurityManager() == null) { 329 // pass vacuously 330 return; 331 } 332 333 final NashornScriptEngineFactory fac = new NashornScriptEngineFactory(); 334 try { 335 fac.getScriptEngine(new String[0], null, new ClassFilter() { 336 @Override 337 public boolean exposeToScripts(final String name) { 338 return true; 339 } 340 }); 341 fail("SecurityException should have been thrown"); 342 } catch (final SecurityException exp) {} 343 } 344 }