8191053: Provide a mechanism to make system's security manager immutable
Make System.setSecurityManager optional to support and add new disallow and allow options to the java.security.manager system property Reviewed-by: alanb, mchung, rriggs, smarks
This commit is contained in:
parent
dde89f72df
commit
d9731f0c54
@ -28,7 +28,6 @@ package java.lang;
|
|||||||
import java.lang.module.ModuleDescriptor;
|
import java.lang.module.ModuleDescriptor;
|
||||||
import java.lang.module.ModuleDescriptor.Exports;
|
import java.lang.module.ModuleDescriptor.Exports;
|
||||||
import java.lang.module.ModuleDescriptor.Opens;
|
import java.lang.module.ModuleDescriptor.Opens;
|
||||||
import java.lang.module.ModuleReference;
|
|
||||||
import java.lang.reflect.Member;
|
import java.lang.reflect.Member;
|
||||||
import java.io.FileDescriptor;
|
import java.io.FileDescriptor;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@ -47,9 +46,7 @@ import java.util.Objects;
|
|||||||
import java.util.PropertyPermission;
|
import java.util.PropertyPermission;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import jdk.internal.module.ModuleBootstrap;
|
|
||||||
import jdk.internal.module.ModuleLoaderMap;
|
import jdk.internal.module.ModuleLoaderMap;
|
||||||
import jdk.internal.reflect.CallerSensitive;
|
import jdk.internal.reflect.CallerSensitive;
|
||||||
import sun.security.util.SecurityConstants;
|
import sun.security.util.SecurityConstants;
|
||||||
@ -81,10 +78,100 @@ import sun.security.util.SecurityConstants;
|
|||||||
* throws a <code>SecurityException</code> if the operation is not
|
* throws a <code>SecurityException</code> if the operation is not
|
||||||
* permitted.
|
* permitted.
|
||||||
* <p>
|
* <p>
|
||||||
* The current security manager is set by the
|
* Environments using a security manager will typically set the security
|
||||||
* <code>setSecurityManager</code> method in class
|
* manager at startup. In the JDK implementation, this is done by setting
|
||||||
* <code>System</code>. The current security manager is obtained
|
* the system property {@code java.security.manager} on the command line to
|
||||||
* by the <code>getSecurityManager</code> method.
|
* the class name of the security manager. It can also be set to the empty
|
||||||
|
* String ("") or the special token "{@code default}" to use the
|
||||||
|
* default {@code java.lang.SecurityManager}. If a class name is specified,
|
||||||
|
* it must be {@code java.lang.SecurityManager} or a public subclass and have
|
||||||
|
* a public no-arg constructor. The class is loaded by the
|
||||||
|
* {@linkplain ClassLoader#getSystemClassLoader() built-in system class loader}
|
||||||
|
* if it is not {@code java.lang.SecurityManager}. If the
|
||||||
|
* {@code java.security.manager} system property is not set, the default value
|
||||||
|
* is {@code null}, which means a security manager will not be set at startup.
|
||||||
|
* <p>
|
||||||
|
* The Java run-time may also allow, but is not required to allow, the security
|
||||||
|
* manager to be set dynamically by invoking the
|
||||||
|
* {@link System#setSecurityManager(SecurityManager) setSecurityManager} method.
|
||||||
|
* In the JDK implementation, if the Java virtual machine is started with
|
||||||
|
* the {@code java.security.manager} system property set to the special token
|
||||||
|
* "{@code disallow}" then a security manager will not be set at startup and
|
||||||
|
* cannot be set dynamically (the
|
||||||
|
* {@link System#setSecurityManager(SecurityManager) setSecurityManager}
|
||||||
|
* method will throw an {@code UnsupportedOperationException}). If the
|
||||||
|
* {@code java.security.manager} system property is not set or is set to the
|
||||||
|
* special token "{@code allow}", then a security manager will not be set at
|
||||||
|
* startup but can be set dynamically. Finally, if the
|
||||||
|
* {@code java.security.manager} system property is set to the class name of
|
||||||
|
* the security manager, or to the empty String ("") or the special token
|
||||||
|
* "{@code default}", then a security manager is set at startup (as described
|
||||||
|
* previously) and can also be subsequently replaced (or disabled) dynamically
|
||||||
|
* (subject to the policy of the currently installed security manager). The
|
||||||
|
* following table illustrates the behavior of the JDK implementation for the
|
||||||
|
* different settings of the {@code java.security.manager} system property:
|
||||||
|
* <table class="striped">
|
||||||
|
* <caption style="display:none">property value,
|
||||||
|
* the SecurityManager set at startup,
|
||||||
|
* can dynamically set a SecurityManager
|
||||||
|
* </caption>
|
||||||
|
* <thead>
|
||||||
|
* <tr>
|
||||||
|
* <th scope="col">Property Value</th>
|
||||||
|
* <th scope="col">The SecurityManager set at startup</th>
|
||||||
|
* <th scope="col">System.setSecurityManager run-time behavior</th>
|
||||||
|
* </tr>
|
||||||
|
* </thead>
|
||||||
|
* <tbody>
|
||||||
|
*
|
||||||
|
* <tr>
|
||||||
|
* <th scope="row">null</th>
|
||||||
|
* <td>None</td>
|
||||||
|
* <td>Success or throws {@code SecurityException} if not permitted by
|
||||||
|
* the currently installed security manager</td>
|
||||||
|
* </tr>
|
||||||
|
*
|
||||||
|
* <tr>
|
||||||
|
* <th scope="row">empty String ("")</th>
|
||||||
|
* <td>{@code java.lang.SecurityManager}</td>
|
||||||
|
* <td>Success or throws {@code SecurityException} if not permitted by
|
||||||
|
* the currently installed security manager</td>
|
||||||
|
* </tr>
|
||||||
|
*
|
||||||
|
* <tr>
|
||||||
|
* <th scope="row">"default"</th>
|
||||||
|
* <td>{@code java.lang.SecurityManager}</td>
|
||||||
|
* <td>Success or throws {@code SecurityException} if not permitted by
|
||||||
|
* the currently installed security manager</td>
|
||||||
|
* </tr>
|
||||||
|
*
|
||||||
|
* <tr>
|
||||||
|
* <th scope="row">"disallow"</th>
|
||||||
|
* <td>None</td>
|
||||||
|
* <td>Always throws {@code UnsupportedOperationException}</td>
|
||||||
|
* </tr>
|
||||||
|
*
|
||||||
|
* <tr>
|
||||||
|
* <th scope="row">"allow"</th>
|
||||||
|
* <td>None</td>
|
||||||
|
* <td>Success or throws {@code SecurityException} if not permitted by
|
||||||
|
* the currently installed security manager</td>
|
||||||
|
* </tr>
|
||||||
|
*
|
||||||
|
* <tr>
|
||||||
|
* <th scope="row">a class name</th>
|
||||||
|
* <td>the named class</td>
|
||||||
|
* <td>Success or throws {@code SecurityException} if not permitted by
|
||||||
|
* the currently installed security manager</td>
|
||||||
|
* </tr>
|
||||||
|
*
|
||||||
|
* </tbody>
|
||||||
|
* </table>
|
||||||
|
* <p> A future release of the JDK may change the default value of the
|
||||||
|
* {@code java.security.manager} system property to "{@code disallow}".
|
||||||
|
* <p>
|
||||||
|
* The current security manager is returned by the
|
||||||
|
* {@link System#getSecurityManager() getSecurityManager} method.
|
||||||
* <p>
|
* <p>
|
||||||
* The special method
|
* The special method
|
||||||
* {@link SecurityManager#checkPermission(java.security.Permission)}
|
* {@link SecurityManager#checkPermission(java.security.Permission)}
|
||||||
@ -221,7 +308,6 @@ import sun.security.util.SecurityConstants;
|
|||||||
* @see java.net.SocketPermission
|
* @see java.net.SocketPermission
|
||||||
* @see java.util.PropertyPermission
|
* @see java.util.PropertyPermission
|
||||||
* @see java.lang.RuntimePermission
|
* @see java.lang.RuntimePermission
|
||||||
* @see java.awt.AWTPermission
|
|
||||||
* @see java.security.Policy Policy
|
* @see java.security.Policy Policy
|
||||||
* @see java.security.SecurityPermission SecurityPermission
|
* @see java.security.SecurityPermission SecurityPermission
|
||||||
* @see java.security.ProtectionDomain
|
* @see java.security.ProtectionDomain
|
||||||
|
@ -72,6 +72,7 @@ import jdk.internal.misc.VM;
|
|||||||
import jdk.internal.logger.LoggerFinderLoader;
|
import jdk.internal.logger.LoggerFinderLoader;
|
||||||
import jdk.internal.logger.LazyLoggers;
|
import jdk.internal.logger.LazyLoggers;
|
||||||
import jdk.internal.logger.LocalizedLoggerWrapper;
|
import jdk.internal.logger.LocalizedLoggerWrapper;
|
||||||
|
import jdk.internal.vm.annotation.Stable;
|
||||||
import sun.reflect.annotation.AnnotationType;
|
import sun.reflect.annotation.AnnotationType;
|
||||||
import sun.nio.ch.Interruptible;
|
import sun.nio.ch.Interruptible;
|
||||||
import sun.security.util.SecurityConstants;
|
import sun.security.util.SecurityConstants;
|
||||||
@ -154,9 +155,18 @@ public final class System {
|
|||||||
*/
|
*/
|
||||||
public static final PrintStream err = null;
|
public static final PrintStream err = null;
|
||||||
|
|
||||||
/* The security manager for the system.
|
// indicates if a security manager is possible
|
||||||
*/
|
private static final int NEVER = 1;
|
||||||
private static volatile SecurityManager security;
|
private static final int MAYBE = 2;
|
||||||
|
private static @Stable int allowSecurityManager;
|
||||||
|
|
||||||
|
// current security manager
|
||||||
|
private static volatile SecurityManager security; // read by VM
|
||||||
|
|
||||||
|
// return true if a security manager is allowed
|
||||||
|
private static boolean allowSecurityManager() {
|
||||||
|
return (allowSecurityManager != NEVER);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reassigns the "standard" input stream.
|
* Reassigns the "standard" input stream.
|
||||||
@ -231,6 +241,7 @@ public final class System {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private static volatile Console cons;
|
private static volatile Console cons;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the unique {@link java.io.Console Console} object associated
|
* Returns the unique {@link java.io.Console Console} object associated
|
||||||
* with the current Java virtual machine, if any.
|
* with the current Java virtual machine, if any.
|
||||||
@ -292,7 +303,7 @@ public final class System {
|
|||||||
private static native void setErr0(PrintStream err);
|
private static native void setErr0(PrintStream err);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the System security.
|
* Sets the system-wide security manager.
|
||||||
*
|
*
|
||||||
* If there is a security manager already installed, this method first
|
* If there is a security manager already installed, this method first
|
||||||
* calls the security manager's {@code checkPermission} method
|
* calls the security manager's {@code checkPermission} method
|
||||||
@ -306,27 +317,46 @@ public final class System {
|
|||||||
* security manager has been established, then no action is taken and
|
* security manager has been established, then no action is taken and
|
||||||
* the method simply returns.
|
* the method simply returns.
|
||||||
*
|
*
|
||||||
* @param s the security manager.
|
* @implNote In the JDK implementation, if the Java virtual machine is
|
||||||
* @throws SecurityException if the security manager has already
|
* started with the system property {@code java.security.manager} set to
|
||||||
* been set and its {@code checkPermission} method
|
* the special token "{@code disallow}" then the {@code setSecurityManager}
|
||||||
* doesn't allow it to be replaced.
|
* method cannot be used to set a security manager.
|
||||||
|
*
|
||||||
|
* @param sm the security manager or {@code null}
|
||||||
|
* @throws SecurityException
|
||||||
|
* if the security manager has already been set and its {@code
|
||||||
|
* checkPermission} method doesn't allow it to be replaced
|
||||||
|
* @throws UnsupportedOperationException
|
||||||
|
* if {@code sm} is non-null and a security manager is not allowed
|
||||||
|
* to be set dynamically
|
||||||
* @see #getSecurityManager
|
* @see #getSecurityManager
|
||||||
* @see SecurityManager#checkPermission
|
* @see SecurityManager#checkPermission
|
||||||
* @see java.lang.RuntimePermission
|
* @see java.lang.RuntimePermission
|
||||||
*/
|
*/
|
||||||
public static void setSecurityManager(final SecurityManager s) {
|
public static void setSecurityManager(SecurityManager sm) {
|
||||||
if (security == null) {
|
if (allowSecurityManager()) {
|
||||||
// ensure image reader is initialized
|
if (security == null) {
|
||||||
Object.class.getResource("java/lang/ANY");
|
// ensure image reader is initialized
|
||||||
}
|
Object.class.getResource("java/lang/ANY");
|
||||||
if (s != null) {
|
}
|
||||||
try {
|
if (sm != null) {
|
||||||
s.checkPackageAccess("java.lang");
|
try {
|
||||||
} catch (Exception e) {
|
// pre-populates the SecurityManager.packageAccess cache
|
||||||
// no-op
|
// to avoid recursive permission checking issues with custom
|
||||||
|
// SecurityManager implementations
|
||||||
|
sm.checkPackageAccess("java.lang");
|
||||||
|
} catch (Exception e) {
|
||||||
|
// no-op
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setSecurityManager0(sm);
|
||||||
|
} else {
|
||||||
|
// security manager not allowed
|
||||||
|
if (sm != null) {
|
||||||
|
throw new UnsupportedOperationException(
|
||||||
|
"Runtime configured to disallow security manager");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setSecurityManager0(s);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static synchronized
|
private static synchronized
|
||||||
@ -335,13 +365,12 @@ public final class System {
|
|||||||
if (sm != null) {
|
if (sm != null) {
|
||||||
// ask the currently installed security manager if we
|
// ask the currently installed security manager if we
|
||||||
// can replace it.
|
// can replace it.
|
||||||
sm.checkPermission(new RuntimePermission
|
sm.checkPermission(new RuntimePermission("setSecurityManager"));
|
||||||
("setSecurityManager"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((s != null) && (s.getClass().getClassLoader() != null)) {
|
if ((s != null) && (s.getClass().getClassLoader() != null)) {
|
||||||
// New security manager class is not on bootstrap classpath.
|
// New security manager class is not on bootstrap classpath.
|
||||||
// Cause policy to get initialized before we install the new
|
// Force policy to get initialized before we install the new
|
||||||
// security manager, in order to prevent infinite loops when
|
// security manager, in order to prevent infinite loops when
|
||||||
// trying to initialize the policy (which usually involves
|
// trying to initialize the policy (which usually involves
|
||||||
// accessing some security and/or system properties, which in turn
|
// accessing some security and/or system properties, which in turn
|
||||||
@ -361,7 +390,7 @@ public final class System {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the system security interface.
|
* Gets the system-wide security manager.
|
||||||
*
|
*
|
||||||
* @return if a security manager has already been established for the
|
* @return if a security manager has already been established for the
|
||||||
* current application, then that security manager is returned;
|
* current application, then that security manager is returned;
|
||||||
@ -369,7 +398,11 @@ public final class System {
|
|||||||
* @see #setSecurityManager
|
* @see #setSecurityManager
|
||||||
*/
|
*/
|
||||||
public static SecurityManager getSecurityManager() {
|
public static SecurityManager getSecurityManager() {
|
||||||
return security;
|
if (allowSecurityManager()) {
|
||||||
|
return security;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -2028,35 +2061,48 @@ public final class System {
|
|||||||
* 3. set TCCL
|
* 3. set TCCL
|
||||||
*
|
*
|
||||||
* This method must be called after the module system initialization.
|
* This method must be called after the module system initialization.
|
||||||
* The security manager and system class loader may be custom class from
|
* The security manager and system class loader may be a custom class from
|
||||||
* the application classpath or modulepath.
|
* the application classpath or modulepath.
|
||||||
*/
|
*/
|
||||||
private static void initPhase3() {
|
private static void initPhase3() {
|
||||||
// set security manager
|
String smProp = System.getProperty("java.security.manager");
|
||||||
String cn = System.getProperty("java.security.manager");
|
if (smProp != null) {
|
||||||
if (cn != null) {
|
switch (smProp) {
|
||||||
if (cn.isEmpty() || "default".equals(cn)) {
|
case "disallow":
|
||||||
System.setSecurityManager(new SecurityManager());
|
allowSecurityManager = NEVER;
|
||||||
} else {
|
break;
|
||||||
try {
|
case "allow":
|
||||||
Class<?> c = Class.forName(cn, false, ClassLoader.getBuiltinAppClassLoader());
|
allowSecurityManager = MAYBE;
|
||||||
Constructor<?> ctor = c.getConstructor();
|
break;
|
||||||
// Must be a public subclass of SecurityManager with
|
case "":
|
||||||
// a public no-arg constructor
|
case "default":
|
||||||
if (!SecurityManager.class.isAssignableFrom(c) ||
|
setSecurityManager(new SecurityManager());
|
||||||
|
allowSecurityManager = MAYBE;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
try {
|
||||||
|
ClassLoader cl = ClassLoader.getBuiltinAppClassLoader();
|
||||||
|
Class<?> c = Class.forName(smProp, false, cl);
|
||||||
|
Constructor<?> ctor = c.getConstructor();
|
||||||
|
// Must be a public subclass of SecurityManager with
|
||||||
|
// a public no-arg constructor
|
||||||
|
if (!SecurityManager.class.isAssignableFrom(c) ||
|
||||||
!Modifier.isPublic(c.getModifiers()) ||
|
!Modifier.isPublic(c.getModifiers()) ||
|
||||||
!Modifier.isPublic(ctor.getModifiers())) {
|
!Modifier.isPublic(ctor.getModifiers())) {
|
||||||
throw new Error("Could not create SecurityManager: " + ctor.toString());
|
throw new Error("Could not create SecurityManager: "
|
||||||
|
+ ctor.toString());
|
||||||
|
}
|
||||||
|
// custom security manager may be in non-exported package
|
||||||
|
ctor.setAccessible(true);
|
||||||
|
SecurityManager sm = (SecurityManager) ctor.newInstance();
|
||||||
|
setSecurityManager(sm);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new InternalError("Could not create SecurityManager", e);
|
||||||
}
|
}
|
||||||
// custom security manager implementation may be in unnamed module
|
allowSecurityManager = MAYBE;
|
||||||
// or a named module but non-exported package
|
|
||||||
ctor.setAccessible(true);
|
|
||||||
SecurityManager sm = (SecurityManager) ctor.newInstance();
|
|
||||||
System.setSecurityManager(sm);
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new Error("Could not create SecurityManager", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
allowSecurityManager = MAYBE;
|
||||||
}
|
}
|
||||||
|
|
||||||
// initializing the system class loader
|
// initializing the system class loader
|
||||||
|
53
test/jdk/java/lang/System/AllowSecurityManager.java
Normal file
53
test/jdk/java/lang/System/AllowSecurityManager.java
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||||
|
*
|
||||||
|
* This code is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 only, as
|
||||||
|
* published by the Free Software Foundation.
|
||||||
|
*
|
||||||
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||||
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||||
|
* version 2 for more details (a copy is included in the LICENSE file that
|
||||||
|
* accompanied this code).
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License version
|
||||||
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||||
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||||
|
*
|
||||||
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
||||||
|
* or visit www.oracle.com if you need additional information or have any
|
||||||
|
* questions.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @test
|
||||||
|
* @bug 8191053
|
||||||
|
* @summary Test that the allow/disallow options of the java.security.manager
|
||||||
|
* system property work correctly
|
||||||
|
* @run main/othervm AllowSecurityManager
|
||||||
|
* @run main/othervm -Djava.security.manager=disallow AllowSecurityManager
|
||||||
|
* @run main/othervm -Djava.security.manager=allow AllowSecurityManager
|
||||||
|
*/
|
||||||
|
|
||||||
|
public class AllowSecurityManager {
|
||||||
|
|
||||||
|
public static void main(String args[]) throws Exception {
|
||||||
|
String prop = System.getProperty("java.security.manager");
|
||||||
|
boolean disallow = "disallow".equals(prop);
|
||||||
|
try {
|
||||||
|
System.setSecurityManager(new SecurityManager());
|
||||||
|
if (disallow) {
|
||||||
|
throw new Exception("System.setSecurityManager did not " +
|
||||||
|
"throw UnsupportedOperationException");
|
||||||
|
}
|
||||||
|
} catch (UnsupportedOperationException uoe) {
|
||||||
|
if (!disallow) {
|
||||||
|
throw new Exception("UnsupportedOperationException " +
|
||||||
|
"unexpectedly thrown by " +
|
||||||
|
"System.setSecurityManager");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user