8020276: interface checks in Invocable.getInterface implementation

Wed, 10 Jul 2013 19:08:04 +0530

author
sundar
date
Wed, 10 Jul 2013 19:08:04 +0530
changeset 427
c501b1666bda
parent 426
a9b74daed4f9
child 428
798e3aa19718

8020276: interface checks in Invocable.getInterface implementation
Reviewed-by: jlaskey, hannesw, attila

src/jdk/nashorn/api/scripting/NashornScriptEngine.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/Context.java file | annotate | diff | comparison | revisions
src/jdk/nashorn/internal/runtime/linker/JavaAdapterFactory.java file | annotate | diff | comparison | revisions
test/src/jdk/nashorn/api/scripting/ScriptEngineTest.java file | annotate | diff | comparison | revisions
     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  }

mercurial