Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move SecurityManager relevant parts to SecurityBridge #1068

Closed
wants to merge 8 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 1 addition & 24 deletions src/org/mozilla/javascript/JavaMembers.java
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,6 @@
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.security.AccessControlContext;
import java.security.AllPermission;
import java.security.Permission;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
Expand All @@ -36,8 +33,6 @@ class JavaMembers {
private static final boolean STRICT_REFLECTIVE_ACCESS =
SourceVersion.latestSupported().ordinal() > 8;

private static final Permission allPermission = new AllPermission();

JavaMembers(Scriptable scope, Class<?> cl) {
this(scope, cl, false);
}
Expand Down Expand Up @@ -770,7 +765,7 @@ static JavaMembers lookupClass(
Map<ClassCache.CacheKey, JavaMembers> ct = cache.getClassCacheMap();

Class<?> cl = dynamicType;
Object secCtx = getSecurityContext();
Object secCtx = SecurityUtilities.getSecurityContext();
for (; ; ) {
members = ct.get(new ClassCache.CacheKey(cl, secCtx));
if (members != null) {
Expand Down Expand Up @@ -827,24 +822,6 @@ private static JavaMembers createJavaMembers(
}
}

private static Object getSecurityContext() {
Object sec = null;
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sec = sm.getSecurityContext();
if (sec instanceof AccessControlContext) {
try {
((AccessControlContext) sec).checkPermission(allPermission);
// if we have allPermission, we do not need to store the
// security object in the cache key
return null;
} catch (SecurityException e) {
}
}
}
return sec;
}

RuntimeException reportMemberNotFound(String memberName) {
return Context.reportRuntimeErrorById(
"msg.java.member.not.found", cl.getName(), memberName);
Expand Down
3 changes: 2 additions & 1 deletion src/org/mozilla/javascript/NativeJavaClass.java
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,8 @@ public Scriptable construct(Context cx, Scriptable scope, Object[] args) {
try {
// When running on Android create an InterfaceAdapter since our
// bytecode generation won't work on Dalvik VM.
if ("Dalvik".equals(System.getProperty("java.vm.name")) && classObject.isInterface()) {
if ("Dalvik".equals(SecurityUtilities.getSystemProperty("java.vm.name"))
&& classObject.isInterface()) {
Object obj =
createInterfaceAdapter(
classObject, ScriptableObject.ensureScriptableObject(args[0]));
Expand Down
3 changes: 3 additions & 0 deletions src/org/mozilla/javascript/PolicySecurityController.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@
* source files are signed in whatever implementation-specific way you're using.
*
* @author Attila Szegedi
* @deprecated This class is only useful in conjunction with {@link SecurityManager}, which is
* deprecated since JDK17 and subject to removal in a future release
*/
@Deprecated
public class PolicySecurityController extends SecurityController {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Class made deprecated. No other code changes

private static final byte[] secureCallerImplBytecode = loadBytecode();

Expand Down
2 changes: 1 addition & 1 deletion src/org/mozilla/javascript/RhinoException.java
Original file line number Diff line number Diff line change
Expand Up @@ -386,7 +386,7 @@ public static StackStyle getStackStyle() {

// Allow us to override default stack style for debugging.
static {
String style = System.getProperty("rhino.stack.style");
String style = SecurityUtilities.getSystemProperty("rhino.stack.style");
if (style != null) {
if ("Rhino".equalsIgnoreCase(style)) {
stackStyle = StackStyle.RHINO;
Expand Down
4 changes: 4 additions & 0 deletions src/org/mozilla/javascript/RhinoSecurityManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,11 @@
* domain of the script that triggered the current action. It is required for JavaAdapters to have
* the same <code>ProtectionDomain</code> as the script code that created them. Embeddings that
* implement their own SecurityManager can use this as base class.
*
* @deprecated This class is only useful in conjunction with {@link SecurityManager}, which is
* deprecated since JDK17 and subject to removal in a future release
*/
@Deprecated
public class RhinoSecurityManager extends SecurityManager {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Class made deprecated. No other code changes


/**
Expand Down
2 changes: 1 addition & 1 deletion src/org/mozilla/javascript/ScriptRuntime.java
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ public static ScriptableObject initStandardObjects(

static String[] getTopPackageNames() {
// Include "android" top package if running on Android
return "Dalvik".equals(System.getProperty("java.vm.name"))
return "Dalvik".equals(SecurityUtilities.getSystemProperty("java.vm.name"))
? new String[] {"java", "javax", "org", "com", "edu", "net", "android"}
: new String[] {"java", "javax", "org", "com", "edu", "net"};
}
Expand Down
7 changes: 6 additions & 1 deletion src/org/mozilla/javascript/SecureCaller.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,12 @@
import java.util.Map;
import java.util.WeakHashMap;

/** @author Attila Szegedi */
/**
* @author Attila Szegedi
* @deprecated This class depends on {@link AccessController}, which is deprecated since JDK17 and
* subject to removal in a future release
*/
@Deprecated
public abstract class SecureCaller {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Class made deprecated. No other code changes (Note: this class is used nowhere in Rhino, so possible used only by embedders)

private static final byte[] secureCallerImplBytecode = loadBytecode();

Expand Down
32 changes: 32 additions & 0 deletions src/org/mozilla/javascript/SecurityBridge.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package org.mozilla.javascript;

import java.security.ProtectionDomain;

/**
* Bridge to security relevant operations, that have to be handled with SecurityManager up to JDK
* 17.
*
* <p>Notice: With JEP411, the SecurityManager is deprecated.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't the

tag be closed?

*
* @author Roland Praml
*/
interface SecurityBridge {

/** @see SecurityUtilities#getSystemProperty(String) */
public String getSystemProperty(final String name);

/** @see SecurityUtilities#getProtectionDomain(Class) */
public ProtectionDomain getProtectionDomain(final Class<?> clazz);

/** @see SecurityUtilities#getScriptProtectionDomain() */
public ProtectionDomain getScriptProtectionDomain();

/** @see SecurityUtilities#getSecurityContext() */
Object getSecurityContext();
}
33 changes: 33 additions & 0 deletions src/org/mozilla/javascript/SecurityBridge_NoOp.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package org.mozilla.javascript;

import java.security.ProtectionDomain;

/** This is a "no-op" implementation of SecurityBridge and should work for JDK17 and beyond. */
public class SecurityBridge_NoOp implements SecurityBridge {

@Override
public String getSystemProperty(final String name) {
return System.getProperty(name);
}

@Override
public ProtectionDomain getProtectionDomain(final Class<?> clazz) {
return clazz.getProtectionDomain();
}

@Override
public ProtectionDomain getScriptProtectionDomain() {
return null;
}

@Override
public Object getSecurityContext() {
return null;
}
}
103 changes: 103 additions & 0 deletions src/org/mozilla/javascript/SecurityBridge_SecurityManager.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
/* -*- Mode: java; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package org.mozilla.javascript;

import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.AllPermission;
import java.security.Permission;
import java.security.PrivilegedAction;
import java.security.ProtectionDomain;

/**
* Code moved from {@link SecurityUtilities}. This implementation makes use of {@link
* SecurityManager} and {@link AccessController} and so on, which is deprecated with JDK17 (see <a
* href='https://openjdk.java.net/jeps/411'>JEP411</a>) - so all related 'java.security' stuff
* should be routed over this class, so that it could be easily replaced by an other implementation
* like {@link SecurityBridge_NoOp}.
*
* <p>This implementation should be work up to JDK17
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to JEP 411, the only API that will not work out the box in Java 18 will be System.setSecurityManager() (to make it work, one needs to set java -Djava.security.manager=allow). Rhino only calls System.setSecurityManager() in SecurityControllerTest, so this implementation should work in Java 18 as well. It is unclear when the actual APIs are going to be removed.

I'd suggest setting java.security.manager=allow in the tests section of build.gradle (or I could do that in a separate PR) to deal with SecurityControllerTest, and avoid mentioning which Java release will/won't work.

*
* @author Attila Szegedi
* @author Roland Praml, FOCONIS AG
*/
@Deprecated
public class SecurityBridge_SecurityManager implements SecurityBridge {
private static final Permission allPermission = new AllPermission();
/**
* Retrieves a system property within a privileged block. Use it only when the property is used
* from within Rhino code and is not passed out of it.
*
* @param name the name of the system property
* @return the value of the system property
*/
@Override
public String getSystemProperty(final String name) {
return AccessController.doPrivileged(
new PrivilegedAction<String>() {
@Override
public String run() {
return System.getProperty(name);
}
});
}
Comment on lines +29 to +47
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The getSystemProperty() method is public and belongs to a public class in an exported package (I mean once Rhino is modularised), allowing the retrieval of system properties with the privileges of Rhino. The comment says "Use it only when the property is used from within Rhino code and is not passed out of it" but the code is not enforcing it: any code with access to the classes in the classpath/modulepath would be allowed to do that.

Probably not a big deal, but I wonder if the security bridge classes could be made package-visible.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could be really a problem


@Override
public ProtectionDomain getProtectionDomain(final Class<?> clazz) {
return AccessController.doPrivileged(
new PrivilegedAction<ProtectionDomain>() {
@Override
public ProtectionDomain run() {
return clazz.getProtectionDomain();
}
});
}

/**
* Look up the top-most element in the current stack representing a script and return its
* protection domain. This relies on the system-wide SecurityManager being an instance of {@link
* RhinoSecurityManager}, otherwise it returns <code>null</code>.
*
* @return The protection of the top-most script in the current stack, or null
*/
@Override
public ProtectionDomain getScriptProtectionDomain() {
final SecurityManager securityManager = System.getSecurityManager();
if (securityManager instanceof RhinoSecurityManager) {
return AccessController.doPrivileged(
new PrivilegedAction<ProtectionDomain>() {
@Override
public ProtectionDomain run() {
Class<?> c =
SecurityUtilities.getCurrentScriptClass(
(RhinoSecurityManager) securityManager);
return c == null ? null : c.getProtectionDomain();
}
});
}
return null;
}

@Override
public Object getSecurityContext() {
Object sec = null;
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sec = sm.getSecurityContext();
if (sec instanceof AccessControlContext) {
try {
((AccessControlContext) sec).checkPermission(allPermission);
// if we have allPermission, we do not need to store the
// security object in the cache key
return null;
} catch (SecurityException e) {
}
}
}
return sec;
}
}
Loading