8021262: Make nashorn access checks consistent with underlying dynalink

Reviewed-by: jlaskey, lagergren, attila
This commit is contained in:
Athijegannathan Sundararajan 2013-07-24 20:28:03 +05:30
parent 27a09545ef
commit 67126cb8fb
23 changed files with 120 additions and 92 deletions

View File

@ -132,7 +132,7 @@
<arg value="-exclude"/>
<arg value="com\.oracle\.nashorn\.runtime\.ScriptRuntime*"/>
<arg value="-exclude"/>
<arg value="jdk\.nashorn\.internal\.javaadapters*"/>
<arg value="jdk\.nashorn\.javaadapters*"/>
<arg value="-exclude"/>
<arg value="jdk\.nashorn\.internal\.objects\.annotations*"/>
<arg value="-exclude"/>

View File

@ -65,7 +65,7 @@ public class SpillObjectCreator extends ObjectCreator {
final int length = keys.size();
final Object[] presetValues = new Object[propertyMap.size()];
final Class clazz = JO.class;
final Class<?> clazz = JO.class;
// Compute constant values
for (int i = 0; i < length; i++) {

View File

@ -44,7 +44,6 @@ import jdk.nashorn.internal.runtime.ConsString;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptEnvironment;
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.runtime.linker.Bootstrap;

View File

@ -55,7 +55,6 @@ import jdk.nashorn.internal.runtime.ECMAException;
import jdk.nashorn.internal.runtime.JSType;
import jdk.nashorn.internal.runtime.Property;
import jdk.nashorn.internal.runtime.PropertyMap;
import jdk.nashorn.internal.runtime.ScriptFunction;
import jdk.nashorn.internal.runtime.ScriptObject;
import jdk.nashorn.internal.runtime.ScriptRuntime;
import jdk.nashorn.internal.runtime.linker.Bootstrap;

View File

@ -40,10 +40,13 @@ import java.lang.reflect.Modifier;
import java.util.concurrent.atomic.AtomicLong;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.CodeSigner;
import java.security.CodeSource;
import java.security.Permissions;
import java.security.PrivilegedAction;
import java.security.ProtectionDomain;
import java.util.Map;
import jdk.internal.org.objectweb.asm.ClassReader;
import jdk.internal.org.objectweb.asm.util.CheckClassAdapter;
@ -201,6 +204,7 @@ public final class Context {
private static final ClassLoader myLoader = Context.class.getClassLoader();
private static final StructureLoader sharedLoader;
private static final AccessControlContext NO_PERMISSIONS_CONTEXT;
static {
sharedLoader = AccessController.doPrivileged(new PrivilegedAction<StructureLoader>() {
@ -209,6 +213,7 @@ public final class Context {
return new StructureLoader(myLoader, null);
}
});
NO_PERMISSIONS_CONTEXT = new AccessControlContext(new ProtectionDomain[] { new ProtectionDomain(null, new Permissions()) });
}
/**
@ -479,7 +484,7 @@ public final class Context {
source = new Source(name, script);
}
} else if (src instanceof Map) {
final Map map = (Map)src;
final Map<?,?> map = (Map<?,?>)src;
if (map.containsKey("script") && map.containsKey("name")) {
final String script = JSType.toString(map.get("script"));
final String name = JSType.toString(map.get("name"));
@ -549,11 +554,14 @@ public final class Context {
* @throws ClassNotFoundException if structure class cannot be resolved
*/
public static Class<?> forStructureClass(final String fullName) throws ClassNotFoundException {
if (System.getSecurityManager() != null && !NashornLoader.isStructureClass(fullName)) {
throw new ClassNotFoundException(fullName);
}
return Class.forName(fullName, true, sharedLoader);
}
/**
* Checks that the given package can be accessed from current call stack.
* Checks that the given package can be accessed from no permissions context.
*
* @param fullName fully qualified package name
* @throw SecurityException if not accessible
@ -563,13 +571,19 @@ public final class Context {
if (index != -1) {
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
@Override
public Void run() {
sm.checkPackageAccess(fullName.substring(0, index));
return null;
}
}, NO_PERMISSIONS_CONTEXT);
}
}
}
/**
* Checks that the given package can be accessed from current call stack.
* Checks that the given package can be accessed from no permissions context.
*
* @param fullName fully qualified package name
* @return true if package is accessible, false otherwise
@ -584,7 +598,7 @@ public final class Context {
}
/**
* Checks that the given Class can be accessed from current call stack and is public.
* Checks that the given Class is public and it can be accessed from no permissions context.
*
* @param clazz Class object to check
* @return true if Class is accessible, false otherwise

View File

@ -118,6 +118,10 @@ abstract class NashornLoader extends SecureClassLoader {
return permCollection;
}
static boolean isStructureClass(final String fullName) {
return fullName.startsWith(SCRIPTS_PKG);
}
/**
* Create a secure URL class loader for the given classpath
* @param classPath classpath for the loader to search from

View File

@ -352,11 +352,15 @@ public final class PropertyMap implements Iterable<Object>, PropertyListener {
return newMap;
}
/*
/**
* Make a new UserAccessorProperty property. getter and setter functions are stored in
* this ScriptObject and slot values are used in property object. Note that slots
* are assigned speculatively and should be added to map before adding other
* properties.
*
* @param key the property name
* @param propertyFlags attribute flags of the property
* @return the newly created UserAccessorProperty
*/
public UserAccessorProperty newUserAccessors(final String key, final int propertyFlags) {
int oldSpillLength = spillLength;

View File

@ -3192,9 +3192,15 @@ public abstract class ScriptObject extends PropertyListenerManager implements Pr
return true;
}
/*
/**
* Make a new UserAccessorProperty property. getter and setter functions are stored in
* this ScriptObject and slot values are used in property object.
*
* @param key the property name
* @param propertyFlags attribute flags of the property
* @param getter getter function for the property
* @param setter setter function for the property
* @return the newly created UserAccessorProperty
*/
protected final UserAccessorProperty newUserAccessors(final String key, final int propertyFlags, final ScriptFunction getter, final ScriptFunction setter) {
final UserAccessorProperty property = getMap().newUserAccessors(key, propertyFlags);

View File

@ -391,7 +391,7 @@ public final class ScriptRuntime {
return construct(target, args);
}
/*
/**
* Call a script function as a constructor with given args.
*
* @param target ScriptFunction object.

View File

@ -384,11 +384,7 @@ public final class Source {
}
final byte[] buf = Files.readAllBytes(file.toPath());
if (cs != null) {
return new String(buf, cs).toCharArray();
} else {
return byteToCharArray(buf);
}
return (cs != null)? new String(buf, cs).toCharArray() : byteToCharArray(buf);
}
/**
@ -465,11 +461,7 @@ public final class Source {
}
private static char[] readFully(final InputStream is, final Charset cs) throws IOException {
if (cs != null) {
return new String(readBytes(is), cs).toCharArray();
} else {
return readFully(is);
}
return (cs != null)? new String(readBytes(is), cs).toCharArray() : readFully(is);
}
private static char[] readFully(final InputStream is) throws IOException {

View File

@ -51,7 +51,6 @@ import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
@ -179,8 +178,6 @@ final class JavaAdapterBytecodeGenerator {
*/
private static final Collection<MethodInfo> EXCLUDED = getExcludedMethods();
private static final Random random = new SecureRandom();
// This is the superclass for our generated adapter.
private final Class<?> superClass;
// Class loader used as the parent for the class loader we'll create to load the generated class. It will be a class
@ -230,12 +227,6 @@ final class JavaAdapterBytecodeGenerator {
superClassName = Type.getInternalName(superClass);
generatedClassName = getGeneratedClassName(superClass, interfaces);
// Randomize the name of the privileged global setter, to make it non-feasible to find.
final long l;
synchronized(random) {
l = random.nextLong();
}
cw.visit(Opcodes.V1_7, ACC_PUBLIC | ACC_SUPER | ACC_FINAL, generatedClassName, null, superClassName, getInternalTypeNames(interfaces));
generateGlobalFields();

View File

@ -73,16 +73,6 @@ final class JavaAdapterClassLoader {
});
}
private static class AdapterLoader extends SecureClassLoader {
AdapterLoader(ClassLoader parent) {
super(parent);
}
}
static boolean isAdapterClass(Class<?> clazz) {
return clazz.getClassLoader() instanceof AdapterLoader;
}
// Note that the adapter class is created in the protection domain of the class/interface being
// extended/implemented, and only the privileged global setter action class is generated in the protection domain
// of Nashorn itself. Also note that the creation and loading of the global setter is deferred until it is
@ -91,7 +81,7 @@ final class JavaAdapterClassLoader {
// with ability to introspect on the class and use setAccessible(true) on it could invoke the method. It's a
// security tradeoff...
private ClassLoader createClassLoader(final ClassLoader parentLoader) {
return new AdapterLoader(parentLoader) {
return new SecureClassLoader(parentLoader) {
private final ClassLoader myLoader = getClass().getClassLoader();
@Override

View File

@ -137,15 +137,6 @@ public final class JavaAdapterFactory {
});
}
/**
* Tells if the given Class is an adapter or support class
* @param clazz Class object
* @return true if the Class given is adapter or support class
*/
public static boolean isAdapterClass(Class<?> clazz) {
return JavaAdapterClassLoader.isAdapterClass(clazz);
}
/**
* Returns whether an instance of the specified class/interface can be generated from a ScriptFunction. Returns true
* iff: the adapter for the class/interface can be created, it is abstract (this includes interfaces), it has at

View File

@ -477,6 +477,7 @@ public class LinkerCallSite extends ChainedCallSite {
/**
* Tracer function that logs a callsite miss
*
* @param desc callsite descriptor string
* @param args arguments to function
*
* @throws Throwable if invocation failes or throws exception/error

View File

@ -169,9 +169,14 @@ final class NashornBottomLinker implements GuardingDynamicLinker {
return ScriptRuntime.safeToString(linkRequest.getArguments()[1]);
}
// Returns @FunctionalInterface annotated interface's single abstract method.
// If not found, returns null
static Method getFunctionalInterfaceMethod(final Class<?> clazz) {
// cache of @FunctionalInterface method of implementor classes
private static final ClassValue<Method> FUNCTIONAL_IFACE_METHOD = new ClassValue<Method>() {
@Override
protected Method computeValue(final Class<?> type) {
return findFunctionalInterfaceMethod(type);
}
private Method findFunctionalInterfaceMethod(final Class<?> clazz) {
if (clazz == null) {
return null;
}
@ -194,6 +199,13 @@ final class NashornBottomLinker implements GuardingDynamicLinker {
}
// did not find here, try super class
return getFunctionalInterfaceMethod(clazz.getSuperclass());
return findFunctionalInterfaceMethod(clazz.getSuperclass());
}
};
// Returns @FunctionalInterface annotated interface's single abstract
// method. If not found, returns null.
static Method getFunctionalInterfaceMethod(final Class<?> clazz) {
return FUNCTIONAL_IFACE_METHOD.get(clazz);
}
}

View File

@ -34,6 +34,7 @@ import jdk.internal.dynalink.linker.LinkRequest;
import jdk.internal.dynalink.linker.LinkerServices;
import jdk.internal.dynalink.linker.TypeBasedGuardingDynamicLinker;
import jdk.internal.dynalink.support.Guards;
import jdk.nashorn.internal.runtime.Context;
import jdk.nashorn.internal.runtime.ECMAErrors;
/**
@ -68,6 +69,9 @@ final class NashornStaticClassLinker implements TypeBasedGuardingDynamicLinker {
final CallSiteDescriptor desc = request.getCallSiteDescriptor();
// We intercept "new" on StaticClass instances to provide additional capabilities
if ("new".equals(desc.getNameToken(CallSiteDescriptor.OPERATOR))) {
// make sure new is on accessible Class
Context.checkPackageAccess(receiverClass.getName());
// Is the class abstract? (This includes interfaces.)
if (NashornLinker.isAbstractClass(receiverClass)) {
// Change this link request into a link request on the adapter class.

View File

@ -76,12 +76,13 @@ final class ReflectionCheckLinker implements TypeBasedGuardingDynamicLinker{
final CallSiteDescriptor desc = requestWithoutContext.getCallSiteDescriptor();
if(CallSiteDescriptorFactory.tokenizeOperators(desc).contains("getProp")) {
if ("static".equals(desc.getNameToken(CallSiteDescriptor.NAME_OPERAND))) {
Context.checkPackageAccess(((Class)self).getName());
// If "getProp:static" passes package access, allow access.
if (Context.isAccessibleClass((Class<?>)self) && !isReflectionClass((Class<?>)self)) {
// If "getProp:static" passes access checks, allow access.
return;
}
}
}
}
checkReflectionPermission(sm);
}
}

View File

@ -44,17 +44,25 @@ function checkClass(name) {
// Not exhaustive - but a representative list of classes
checkClass("jdk.nashorn.internal.codegen.Compiler");
checkClass("jdk.nashorn.internal.codegen.objects.MapCreator");
checkClass("jdk.nashorn.internal.codegen.types.Type");
checkClass("jdk.nashorn.internal.ir.Node");
checkClass("jdk.nashorn.internal.ir.FunctionNode");
checkClass("jdk.nashorn.internal.ir.debug.JSONWriter");
checkClass("jdk.nashorn.internal.ir.visitor.NodeVisitor");
checkClass("jdk.nashorn.internal.lookup.MethodHandleFactory");
checkClass("jdk.nashorn.internal.objects.Global");
checkClass("jdk.nashorn.internal.parser.AbstractParser");
checkClass("jdk.nashorn.internal.parser.Parser");
checkClass("jdk.nashorn.internal.parser.JSONParser");
checkClass("jdk.nashorn.internal.parser.Lexer");
checkClass("jdk.nashorn.internal.parser.Scanner");
checkClass("jdk.nashorn.internal.runtime.Context");
checkClass("jdk.nashorn.internal.runtime.arrays.ArrayData");
checkClass("jdk.nashorn.internal.runtime.linker.Bootstrap");
checkClass("jdk.nashorn.internal.runtime.options.Option");
checkClass("jdk.nashorn.internal.runtime.regexp.RegExp");
checkClass("jdk.nashorn.internal.scripts.JO");
checkClass("jdk.nashorn.tools.Shell");
checkClass("jdk.internal.dynalink.CallSiteDescriptor");
checkClass("jdk.internal.dynalink.beans.StaticClass");
checkClass("jdk.internal.dynalink.linker.LinkRequest");

View File

@ -39,20 +39,21 @@
* and FunctionNode because of package-access check and so reflective calls.
*/
var Parser = Java.type("jdk.nashorn.internal.parser.Parser")
var Compiler = Java.type("jdk.nashorn.internal.codegen.Compiler")
var Context = Java.type("jdk.nashorn.internal.runtime.Context")
var ScriptEnvironment = Java.type("jdk.nashorn.internal.runtime.ScriptEnvironment")
var Source = Java.type("jdk.nashorn.internal.runtime.Source")
var FunctionNode = Java.type("jdk.nashorn.internal.ir.FunctionNode")
var Block = Java.type("jdk.nashorn.internal.ir.Block")
var VarNode = Java.type("jdk.nashorn.internal.ir.VarNode")
var ExpressionStatement = Java.type("jdk.nashorn.internal.ir.ExpressionStatement")
var UnaryNode = Java.type("jdk.nashorn.internal.ir.UnaryNode")
var BinaryNode = Java.type("jdk.nashorn.internal.ir.BinaryNode")
var ThrowErrorManager = Java.type("jdk.nashorn.internal.runtime.Context$ThrowErrorManager")
var ErrorManager = Java.type("jdk.nashorn.internal.runtime.ErrorManager")
var Debug = Java.type("jdk.nashorn.internal.runtime.Debug")
var forName = java.lang.Class["forName(String)"];
var Parser = forName("jdk.nashorn.internal.parser.Parser").static
var Compiler = forName("jdk.nashorn.internal.codegen.Compiler").static
var Context = forName("jdk.nashorn.internal.runtime.Context").static
var ScriptEnvironment = forName("jdk.nashorn.internal.runtime.ScriptEnvironment").static
var Source = forName("jdk.nashorn.internal.runtime.Source").static
var FunctionNode = forName("jdk.nashorn.internal.ir.FunctionNode").static
var Block = forName("jdk.nashorn.internal.ir.Block").static
var VarNode = forName("jdk.nashorn.internal.ir.VarNode").static
var ExpressionStatement = forName("jdk.nashorn.internal.ir.ExpressionStatement").static
var UnaryNode = forName("jdk.nashorn.internal.ir.UnaryNode").static
var BinaryNode = forName("jdk.nashorn.internal.ir.BinaryNode").static
var ThrowErrorManager = forName("jdk.nashorn.internal.runtime.Context$ThrowErrorManager").static
var ErrorManager = forName("jdk.nashorn.internal.runtime.ErrorManager").static
var Debug = forName("jdk.nashorn.internal.runtime.Debug").static
var parseMethod = Parser.class.getMethod("parse");
var compileMethod = Compiler.class.getMethod("compile", FunctionNode.class);

View File

@ -29,9 +29,9 @@
* @test
* @run
*/
var R = Java.type("jdk.nashorn.internal.test.models.InternalRunnable")
var r1 = R.class.newInstance()
var InternalRunnableSuperclass = Java.type("jdk.nashorn.test.models.InternalRunnableSuperclass");
var r1 = InternalRunnableSuperclass.makeInternalRunnable();
r1.run() // Can execute method from an implemented non-restricted interface
print(r1.toString()) // Can execute public method from a superclass
@ -41,5 +41,5 @@ print(r1.invisibleProperty === undefined) // Can't see any other properties
print(r1.canSeeThisField === undefined) // Can't see fields from superclasses
print(r1.canNotSeeThisField === undefined) // Can't see its own fields
var r2 = new (Java.type("jdk.nashorn.test.models.InternalRunnableSuperclass"))
var r2 = new InternalRunnableSuperclass();
print(r2.canSeeThisField) // Superclass field works fine on its own

View File

@ -27,8 +27,9 @@
* @test
* @run
*/
var InternalRunnableSuperclass = Java.type("jdk.nashorn.test.models.InternalRunnableSuperclass");
try {
new (Java.type("jdk.nashorn.internal.test.models.InternalRunnable"))
new (InternalRunnableSuperclass.getInternalRunnableType())();
} catch(e) {
print(e)
}

View File

@ -1 +1 @@
TypeError: Can not construct jdk.nashorn.internal.test.models.InternalRunnable with the passed arguments; they do not match any of its constructor signatures.
java.security.AccessControlException: access denied ("java.lang.RuntimePermission" "accessClassInPackage.jdk.nashorn.internal.test.models")

View File

@ -25,6 +25,9 @@
package jdk.nashorn.test.models;
import jdk.internal.dynalink.beans.StaticClass;
import jdk.nashorn.internal.test.models.InternalRunnable;
/**
* Acts as a non-restricted superclass for a restricted class.
*
@ -32,4 +35,11 @@ package jdk.nashorn.test.models;
public class InternalRunnableSuperclass {
public final int canSeeThisField = 19;
public static Object makeInternalRunnable() {
return new InternalRunnable();
}
public static StaticClass getInternalRunnableType() {
return StaticClass.forClass(InternalRunnable.class);
}
}