Wed, 10 Jul 2013 19:08:04 +0530
8020276: interface checks in Invocable.getInterface implementation
Reviewed-by: jlaskey, hannesw, attila
1.1 --- a/src/jdk/nashorn/api/scripting/NashornScriptEngine.java Wed Jul 10 10:54:19 2013 +0200 1.2 +++ b/src/jdk/nashorn/api/scripting/NashornScriptEngine.java Wed Jul 10 19:08:04 2013 +0530 1.3 @@ -33,6 +33,7 @@ 1.4 import java.io.InputStreamReader; 1.5 import java.io.Reader; 1.6 import java.lang.reflect.Method; 1.7 +import java.lang.reflect.Modifier; 1.8 import java.net.URL; 1.9 import java.nio.charset.Charset; 1.10 import java.security.AccessController; 1.11 @@ -184,6 +185,23 @@ 1.12 } 1.13 1.14 private <T> T getInterfaceInner(final Object self, final Class<T> clazz) { 1.15 + if (clazz == null || !clazz.isInterface()) { 1.16 + throw new IllegalArgumentException("interface Class expected"); 1.17 + } 1.18 + 1.19 + // perform security access check as early as possible 1.20 + final SecurityManager sm = System.getSecurityManager(); 1.21 + if (sm != null) { 1.22 + if (! Modifier.isPublic(clazz.getModifiers())) { 1.23 + throw new SecurityException("attempt to implement non-public interfce: " + clazz); 1.24 + } 1.25 + final String fullName = clazz.getName(); 1.26 + final int index = fullName.lastIndexOf('.'); 1.27 + if (index != -1) { 1.28 + sm.checkPackageAccess(fullName.substring(0, index)); 1.29 + } 1.30 + } 1.31 + 1.32 final ScriptObject realSelf; 1.33 final ScriptObject ctxtGlobal = getNashornGlobalFrom(context); 1.34 if(self == null) { 1.35 @@ -193,6 +211,7 @@ 1.36 } else { 1.37 realSelf = (ScriptObject)self; 1.38 } 1.39 + 1.40 try { 1.41 final ScriptObject oldGlobal = getNashornGlobal(); 1.42 try {
2.1 --- a/src/jdk/nashorn/internal/runtime/Context.java Wed Jul 10 10:54:19 2013 +0200 2.2 +++ b/src/jdk/nashorn/internal/runtime/Context.java Wed Jul 10 19:08:04 2013 +0530 2.3 @@ -36,6 +36,7 @@ 2.4 import java.io.PrintWriter; 2.5 import java.lang.invoke.MethodHandle; 2.6 import java.lang.invoke.MethodHandles; 2.7 +import java.util.concurrent.atomic.AtomicLong; 2.8 import java.net.MalformedURLException; 2.9 import java.net.URL; 2.10 import java.security.AccessControlContext; 2.11 @@ -203,7 +204,7 @@ 2.12 private final ErrorManager errors; 2.13 2.14 /** Unique id for script. Used only when --loader-per-compile=false */ 2.15 - private long uniqueScriptId; 2.16 + private final AtomicLong uniqueScriptId; 2.17 2.18 private static final ClassLoader myLoader = Context.class.getClassLoader(); 2.19 private static final StructureLoader sharedLoader; 2.20 @@ -263,7 +264,13 @@ 2.21 this.env = new ScriptEnvironment(options, out, err); 2.22 this._strict = env._strict; 2.23 this.appLoader = appLoader; 2.24 - this.scriptLoader = env._loader_per_compile? null : createNewLoader(); 2.25 + if (env._loader_per_compile) { 2.26 + this.scriptLoader = null; 2.27 + this.uniqueScriptId = null; 2.28 + } else { 2.29 + this.scriptLoader = createNewLoader(); 2.30 + this.uniqueScriptId = new AtomicLong(); 2.31 + } 2.32 this.errors = errors; 2.33 2.34 // if user passed -classpath option, make a class loader with that and set it as 2.35 @@ -825,7 +832,7 @@ 2.36 return new Global(this); 2.37 } 2.38 2.39 - private synchronized long getUniqueScriptId() { 2.40 - return uniqueScriptId++; 2.41 + private long getUniqueScriptId() { 2.42 + return uniqueScriptId.getAndIncrement(); 2.43 } 2.44 }
3.1 --- a/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java Wed Jul 10 10:54:19 2013 +0200 3.2 +++ b/src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java Wed Jul 10 19:08:04 2013 +0530 3.3 @@ -99,6 +99,17 @@ 3.4 */ 3.5 public static StaticClass getAdapterClassFor(final Class<?>[] types, ScriptObject classOverrides) { 3.6 assert types != null && types.length > 0; 3.7 + final SecurityManager sm = System.getSecurityManager(); 3.8 + if (sm != null) { 3.9 + for (Class type : types) { 3.10 + // check for restricted package access 3.11 + final String fullName = type.getName(); 3.12 + final int index = fullName.lastIndexOf('.'); 3.13 + if (index != -1) { 3.14 + sm.checkPackageAccess(fullName.substring(0, index)); 3.15 + } 3.16 + } 3.17 + } 3.18 return getAdapterInfo(types).getAdapterClassFor(classOverrides); 3.19 } 3.20
4.1 --- a/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java Wed Jul 10 10:54:19 2013 +0200 4.2 +++ b/test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java Wed Jul 10 19:08:04 2013 +0530 4.3 @@ -36,6 +36,7 @@ 4.4 import java.lang.reflect.Method; 4.5 import java.util.HashMap; 4.6 import java.util.Map; 4.7 +import java.util.Objects; 4.8 import java.util.concurrent.Callable; 4.9 import javax.script.Bindings; 4.10 import javax.script.Compilable; 4.11 @@ -345,6 +346,23 @@ 4.12 } 4.13 4.14 @Test 4.15 + /** 4.16 + * Try passing non-interface Class object for interface implementation. 4.17 + */ 4.18 + public void getNonInterfaceGetInterfaceTest() { 4.19 + final ScriptEngineManager manager = new ScriptEngineManager(); 4.20 + final ScriptEngine engine = manager.getEngineByName("nashorn"); 4.21 + try { 4.22 + log(Objects.toString(((Invocable)engine).getInterface(Object.class))); 4.23 + fail("Should have thrown IllegalArgumentException"); 4.24 + } catch (final Exception exp) { 4.25 + if (! (exp instanceof IllegalArgumentException)) { 4.26 + fail("IllegalArgumentException expected, got " + exp); 4.27 + } 4.28 + } 4.29 + } 4.30 + 4.31 + @Test 4.32 public void accessGlobalTest() { 4.33 final ScriptEngineManager m = new ScriptEngineManager(); 4.34 final ScriptEngine e = m.getEngineByName("nashorn"); 4.35 @@ -927,4 +945,35 @@ 4.36 Assert.assertEquals(itf.test1(42, "a", "b"), "i == 42, strings instanceof java.lang.String[] == true, strings == [a, b]"); 4.37 Assert.assertEquals(itf.test2(44, "c", "d", "e"), "arguments[0] == 44, arguments[1] instanceof java.lang.String[] == true, arguments[1] == [c, d, e]"); 4.38 } 4.39 + 4.40 + @Test 4.41 + /** 4.42 + * Check that script can't implement sensitive package interfaces. 4.43 + */ 4.44 + public void checkSensitiveInterfaceImplTest() throws ScriptException { 4.45 + final ScriptEngineManager m = new ScriptEngineManager(); 4.46 + final ScriptEngine e = m.getEngineByName("nashorn"); 4.47 + final Object[] holder = new Object[1]; 4.48 + e.put("holder", holder); 4.49 + // put an empty script object into array 4.50 + e.eval("holder[0] = {}"); 4.51 + // holder[0] is an object of some subclass of ScriptObject 4.52 + Class ScriptObjectClass = holder[0].getClass().getSuperclass(); 4.53 + Class PropertyAccessClass = ScriptObjectClass.getInterfaces()[0]; 4.54 + // implementation methods for PropertyAccess class 4.55 + e.eval("function set() {}; function get() {}; function getInt(){} " + 4.56 + "function getDouble(){}; function getLong() {}; " + 4.57 + "this.delete = function () {}; function has() {}; " + 4.58 + "function hasOwnProperty() {}"); 4.59 + 4.60 + // get implementation of a restricted package interface 4.61 + try { 4.62 + log(Objects.toString(((Invocable)e).getInterface(PropertyAccessClass))); 4.63 + fail("should have thrown SecurityException"); 4.64 + } catch (final Exception exp) { 4.65 + if (! (exp instanceof SecurityException)) { 4.66 + fail("SecurityException expected, got " + exp); 4.67 + } 4.68 + } 4.69 + } 4.70 }