--- old/src/java.base/share/classes/java/security/Policy.java 2015-05-05 17:33:32.834525314 -0400 +++ new/src/java.base/share/classes/java/security/Policy.java 2015-05-05 17:33:32.446534078 -0400 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2015, 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 @@ -49,7 +49,8 @@ * implementation (a default subclass implementation of this abstract class). * The default Policy implementation can be changed by setting the value * of the {@code policy.provider} security property to the fully qualified - * name of the desired Policy subclass implementation. + * name of the desired Policy subclass implementation. The system class loader + * is used to load this class. * *

Application code can directly subclass Policy to provide a custom * implementation. In addition, an instance of a Policy object can be @@ -111,6 +112,10 @@ private static final Debug debug = Debug.getInstance("policy"); + // Default policy provider + private static final String DEFAULT_POLICY = + "sun.security.provider.PolicyFile"; + // Cache mapping ProtectionDomain.Key to PermissionCollection private WeakHashMap pdMapping; @@ -169,74 +174,7 @@ synchronized (Policy.class) { PolicyInfo pinfo = policy.get(); if (pinfo.policy == null) { - String policy_class = AccessController.doPrivileged( - new PrivilegedAction() { - public String run() { - return Security.getProperty("policy.provider"); - } - }); - if (policy_class == null) { - policy_class = "sun.security.provider.PolicyFile"; - } - - try { - pinfo = new PolicyInfo( - (Policy) Class.forName(policy_class).newInstance(), - true); - } catch (Exception e) { - /* - * The policy_class seems to be an extension - * so we have to bootstrap loading it via a policy - * provider that is on the bootclasspath. - * If it loads then shift gears to using the configured - * provider. - */ - - // install the bootstrap provider to avoid recursion - Policy polFile = new sun.security.provider.PolicyFile(); - pinfo = new PolicyInfo(polFile, false); - policy.set(pinfo); - - final String pc = policy_class; - Policy pol = AccessController.doPrivileged( - new PrivilegedAction() { - public Policy run() { - try { - ClassLoader cl = - ClassLoader.getSystemClassLoader(); - // we want the extension loader - ClassLoader extcl = null; - while (cl != null) { - extcl = cl; - cl = cl.getParent(); - } - return (extcl != null ? (Policy)Class.forName( - pc, true, extcl).newInstance() : null); - } catch (Exception e) { - if (debug != null) { - debug.println("policy provider " + - pc + - " not available"); - e.printStackTrace(); - } - return null; - } - } - }); - /* - * if it loaded install it as the policy provider. Otherwise - * continue to use the system default implementation - */ - if (pol != null) { - pinfo = new PolicyInfo(pol, true); - } else { - if (debug != null) { - debug.println("using sun.security.provider.PolicyFile"); - } - pinfo = new PolicyInfo(polFile, true); - } - } - policy.set(pinfo); + return loadPolicyProvider(); } return pinfo.policy; } @@ -245,6 +183,78 @@ } /** + * Loads and instantiates a Policy implementation specified by the + * policy.provider security property. Note that this method should only + * be called by getPolicyNoCheck and from within a synchronized block with + * an intrinsic lock on the Policy.class. + */ + private static Policy loadPolicyProvider() { + String policyProvider = + AccessController.doPrivileged((PrivilegedAction) + () -> Security.getProperty("policy.provider")); + + if (policyProvider == null || policyProvider.isEmpty() || + policyProvider.equals(DEFAULT_POLICY)) + { + Policy polFile = new sun.security.provider.PolicyFile(); + policy.set(new PolicyInfo(polFile, true)); + return polFile; + } + + Class pc = null; + Policy polFile = null; + try { + // check if policyProvider is on the bootclasspath + pc = Class.forName(policyProvider, false, null); + } catch (ClassNotFoundException cnfe) { + /* + * The policyProvider seems to be on the classpath so we have + * to bootstrap load it via a policy provider that is on the + * bootclasspath. If it loads then shift gears to using the + * configured provider. + */ + + // install the bootstrap provider to avoid recursion + polFile = new sun.security.provider.PolicyFile(); + policy.set(new PolicyInfo(polFile, false)); + } + + Policy pol = null; + try { + if (pc == null) { + pol = AccessController.doPrivileged( + (PrivilegedExceptionAction) () -> + { + ClassLoader scl = ClassLoader.getSystemClassLoader(); + if (scl == null) { + return null; + } + Class c = Class.forName(policyProvider, true, scl); + return (Policy)c.newInstance(); + }); + } else { + pol = (Policy)pc.newInstance(); + } + } catch (Exception e) { + if (debug != null) { + debug.println("policy provider " + policyProvider + + " not available"); + e.printStackTrace(); + } + } + if (pol == null) { + // Use the system default implementation + if (debug != null) { + debug.println("using " + DEFAULT_POLICY); + } + pol = polFile != null ? polFile + : new sun.security.provider.PolicyFile(); + } + policy.set(new PolicyInfo(pol, true)); + return pol; + } + + /** * Sets the system-wide Policy object. This method first calls * {@code SecurityManager.checkPermission} with a * {@code SecurityPermission("setPolicy")} --- old/src/java.base/share/conf/security/java.security 2015-05-05 17:33:34.006498845 -0400 +++ new/src/java.base/share/conf/security/java.security 2015-05-05 17:33:33.710505530 -0400 @@ -156,7 +156,8 @@ # # Class to instantiate as the system Policy. This is the name of the class -# that will be used as the Policy object. +# that will be used as the Policy object. The system class loader is used to +# locate this class. # policy.provider=sun.security.provider.PolicyFile --- /dev/null 2015-05-01 09:37:46.994868884 -0400 +++ new/test/java/security/Policy/PolicyProvider/CustomPolicy.java 2015-05-05 17:33:34.766481680 -0400 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2015, 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. + */ + +import java.security.AccessController; +import java.security.Permission; +import java.security.Policy; +import java.security.PrivilegedAction; +import java.security.ProtectionDomain; + +public class CustomPolicy extends Policy { + + // the ProtectionDomain of CustomPolicy + private final ProtectionDomain policyPd; + + public CustomPolicy() { + policyPd = AccessController.doPrivileged( + (PrivilegedAction) + () -> this.getClass().getProtectionDomain()); + } + + @Override + public boolean implies(ProtectionDomain pd, Permission perm) { + System.out.println("CustomPolicy.implies"); + + // If the protection domain is the same as CustomPolicy, then + // we return true. This is to prevent recursive permission checks + // that lead to StackOverflow errors when the policy implementation + // performs a sensitive operation that triggers a permission check, + // for example, as below. + if (pd == policyPd) { + return true; + } + + // Do something that triggers a permission check to make sure that + // we don't cause a StackOverflow error. + String home = AccessController.doPrivileged( + (PrivilegedAction) () -> System.getProperty("user.home")); + + return true; + } +} --- /dev/null 2015-05-01 09:37:46.994868884 -0400 +++ new/test/java/security/Policy/PolicyProvider/UseSystemClassLoader.java 2015-05-05 17:33:35.566463611 -0400 @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2015, 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. + */ + +import java.io.File; +import java.net.URL; +import java.security.Policy; +import java.security.Security; + +/* + * @test + * @bug 8075706 + * @summary Check that a custom policy provider can be loaded from the classpath + * @run main/othervm UseSystemClassLoader CUSTOM + * @run main/othervm UseSystemClassLoader DEFAULT + * @run main/othervm UseSystemClassLoader NOT_AVAIL + * @run main/othervm UseSystemClassLoader NOT_SET + */ + +public class UseSystemClassLoader { + + enum Type { + CUSTOM, DEFAULT, NOT_AVAIL, NOT_SET + }; + + public static void main(String[] args) throws Exception { + + Type t = Type.valueOf(args[0]); + + // We can't use the jtreg java.security.policy option to specify + // the policy file because that causes the default JDK policy provider + // to be set and once set, we cannot change it. So, instead we use the + // policy.url security property. + File file = new File(System.getProperty("test.src"), "test.policy"); + URL policyURL = file.toURI().toURL(); + Security.setProperty("policy.url.1", policyURL.toString()); + + switch (t) { + case CUSTOM: + // Set policy.provider to our custom policy provider + Security.setProperty("policy.provider", "CustomPolicy"); + break; + case NOT_AVAIL: + // Set policy.provider to a non-existent policy provider + Security.setProperty("policy.provider", "NonExistentPolicy"); + break; + case DEFAULT: + // Don't set policy.provider (leave default) + break; + case NOT_SET: + // Set policy.provider to empty string + Security.setProperty("policy.provider", ""); + break; + } + + System.setSecurityManager(new SecurityManager()); + Policy p = Policy.getPolicy(); + switch (t) { + case CUSTOM: + // check that the custom policy provider has been set + if (!(p instanceof CustomPolicy)) { + throw new Exception("CustomPolicy was not set"); + } + break; + case NOT_AVAIL: + case DEFAULT: + case NOT_SET: + // check that the default policy provider has been set + if (!(p instanceof sun.security.provider.PolicyFile)) { + throw new Exception("default provider was not set"); + } + break; + } + } +} --- /dev/null 2015-05-01 09:37:46.994868884 -0400 +++ new/test/java/security/Policy/PolicyProvider/test.policy 2015-05-05 17:33:36.290447260 -0400 @@ -0,0 +1,9 @@ +grant { + permission java.lang.RuntimePermission "createSecurityManager"; + permission java.lang.RuntimePermission "setSecurityManager"; + permission java.security.SecurityPermission "setProperty.policy.provider"; + permission java.security.SecurityPermission "getPolicy"; + permission java.util.PropertyPermission "user.home", "read"; + permission java.lang.RuntimePermission "getProtectionDomain"; + permission java.lang.RuntimePermission "accessClassInPackage.sun.security.provider"; +};