changeset 14975:f396f4a7ee5d

8244473: Contextualize registration for JNDI Reviewed-by: bae, andrew
author mbalao
date Wed, 07 Apr 2021 05:55:34 +0100
parents a7ef81ab119b
children 412d2b1381a4
files src/share/classes/com/sun/jndi/ldap/Obj.java src/share/classes/com/sun/jndi/ldap/VersionHelper12.java src/share/classes/com/sun/naming/internal/ObjectFactoriesFilter.java src/share/classes/com/sun/naming/internal/VersionHelper.java src/share/classes/com/sun/naming/internal/VersionHelper12.java src/share/classes/javax/naming/spi/NamingManager.java src/share/lib/security/java.security-aix src/share/lib/security/java.security-linux src/share/lib/security/java.security-macosx src/share/lib/security/java.security-solaris src/share/lib/security/java.security-windows
diffstat 11 files changed, 300 insertions(+), 15 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/classes/com/sun/jndi/ldap/Obj.java	Sat Mar 27 19:01:26 2021 +0000
+++ b/src/share/classes/com/sun/jndi/ldap/Obj.java	Wed Apr 07 05:55:34 2021 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2011, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2020, 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
@@ -235,6 +235,9 @@
         String[] codebases = getCodebases(attrs.get(JAVA_ATTRIBUTES[CODEBASE]));
         try {
             if ((attr = attrs.get(JAVA_ATTRIBUTES[SERIALIZED_DATA])) != null) {
+                if (!VersionHelper12.isSerialDataAllowed()) {
+                    throw new NamingException("Object deserialization is not allowed");
+                }
                 ClassLoader cl = helper.getURLClassLoader(codebases);
                 return deserializeObject((byte[])attr.get(), cl);
             } else if ((attr = attrs.get(JAVA_ATTRIBUTES[REMOTE_LOC])) != null) {
--- a/src/share/classes/com/sun/jndi/ldap/VersionHelper12.java	Sat Mar 27 19:01:26 2021 +0000
+++ b/src/share/classes/com/sun/jndi/ldap/VersionHelper12.java	Wed Apr 07 05:55:34 2021 +0100
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1999, 2013, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1999, 2020, 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
@@ -39,19 +39,48 @@
     private static final String TRUST_URL_CODEBASE_PROPERTY =
         "com.sun.jndi.ldap.object.trustURLCodebase";
 
+    // System property to control whether classes are allowed to be loaded from
+    // 'javaSerializedData' attribute
+    private static final String TRUST_SERIAL_DATA_PROPERTY =
+        "com.sun.jndi.ldap.object.trustSerialData";
+
+    /**
+     * Determines whether objects may be deserialized from the content of
+     * 'javaSerializedData' attribute.
+     */
+    private static final boolean trustSerialData;
+
     // Determine whether classes may be loaded from an arbitrary URL code base.
-    private static final String trustURLCodebase =
-        AccessController.doPrivileged(
-            new PrivilegedAction<String>() {
-                public String run() {
-                    return System.getProperty(TRUST_URL_CODEBASE_PROPERTY,
-                            "false");
-                }
-            }
-        );
+    private static final boolean trustURLCodebase;
+
+    static {
+        String trust = getPrivilegedProperty(TRUST_URL_CODEBASE_PROPERTY, "false");
+        trustURLCodebase = "true".equalsIgnoreCase(trust);
+        String trustSDString = getPrivilegedProperty(TRUST_SERIAL_DATA_PROPERTY, "true");
+        trustSerialData = "true".equalsIgnoreCase(trustSDString);
+    }
+
+    private static String getPrivilegedProperty(String propertyName, String defaultVal) {
+        PrivilegedAction<String> action = () -> System.getProperty(propertyName, defaultVal);
+        if (System.getSecurityManager() == null) {
+            return action.run();
+        } else {
+            return AccessController.doPrivileged(action);
+        }
+    }
 
     VersionHelper12() {} // Disallow external from creating one of these.
 
+    /**
+     * Returns true if deserialization of objects from 'javaSerializedData'
+     * LDAP attribute is allowed.
+     *
+     * @return true if deserialization is allowed; false - otherwise
+     */
+    public static boolean isSerialDataAllowed() {
+        return trustSerialData;
+    }
+
     ClassLoader getURLClassLoader(String[] url)
         throws MalformedURLException {
             ClassLoader parent = getContextClassLoader();
@@ -60,7 +89,7 @@
              * the system property com.sun.jndi.ldap.object.trustURLCodebase
              * has been set to "true".
              */
-            if (url != null && "true".equalsIgnoreCase(trustURLCodebase)) {
+            if (url != null && trustURLCodebase) {
                 return URLClassLoader.newInstance(getUrlArray(url), parent);
             } else {
                 return parent;
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/share/classes/com/sun/naming/internal/ObjectFactoriesFilter.java	Wed Apr 07 05:55:34 2021 +0100
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2020, 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.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * 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.
+ */
+
+package com.sun.naming.internal;
+
+import javax.naming.Reference;
+
+import sun.misc.ObjectInputFilter;
+import sun.misc.ObjectInputFilter.FilterInfo;
+import sun.misc.ObjectInputFilter.Status;
+
+import sun.security.util.SecurityProperties;
+
+/**
+ * This class implements the filter that validates object factories classes instantiated
+ * during {@link Reference} lookups.
+ * There is one system-wide filter instance per VM that can be set via
+ * the {@code "jdk.jndi.object.factoriesFilter"} system property value, or via
+ * setting the property in the security properties file. The system property value supersedes
+ * the security property value. If none of the properties are specified the default
+ * "*" value is used.
+ * The filter is implemented as {@link ObjectInputFilter} with capabilities limited to the
+ * validation of a factory's class types only ({@linkplain FilterInfo#serialClass()}).
+ * Array length, number of object references, depth, and stream size filtering capabilities are
+ * not supported by the filter.
+ */
+public final class ObjectFactoriesFilter {
+
+    /**
+     * Checks if serial filter configured with {@code "jdk.jndi.object.factoriesFilter"}
+     * system property value allows instantiation of the specified objects factory class.
+     * If the filter result is not {@linkplain Status#REJECTED REJECTED}, the filter will
+     * allow the instantiation of objects factory class.
+     *
+     * @param factoryClass objects factory class
+     * @return true - if the factory is allowed to be instantiated; false - otherwise
+     */
+    public static boolean canInstantiateObjectsFactory(Class<?> factoryClass) {
+        return checkInput(() -> factoryClass);
+    }
+
+    private static boolean checkInput(FactoryInfo factoryInfo) {
+        Status result = GLOBAL.checkInput(factoryInfo);
+        return result != Status.REJECTED;
+    }
+
+    // FilterInfo to check if objects factory class is allowed by the system-wide
+    // filter. Array length, number of object references, depth, and stream size
+    // capabilities are ignored.
+    @FunctionalInterface
+    private interface FactoryInfo extends FilterInfo {
+        @Override
+        default long arrayLength() {
+            return -1;
+        }
+
+        @Override
+        default long depth() {
+            return 1;
+        }
+
+        @Override
+        default long references() {
+            return 0;
+        }
+
+        @Override
+        default long streamBytes() {
+            return 0;
+        }
+    }
+
+    // Prevent instantiation of the factories filter class
+     private ObjectFactoriesFilter() {
+         throw new InternalError("Not instantiable");
+     }
+
+    // System property name that contains the patterns to filter object factory names
+    private static final String FACTORIES_FILTER_PROPNAME = "jdk.jndi.object.factoriesFilter";
+
+    // Default system property value that allows the load of any object factory classes
+    private static final String DEFAULT_SP_VALUE = "*";
+
+    // System wide object factories filter constructed from the system property
+    private static final ObjectInputFilter GLOBAL =
+            ObjectInputFilter.Config.createFilter(getFilterPropertyValue());
+
+    // Get security or system property value
+    private static String getFilterPropertyValue() {
+        String propVal = SecurityProperties.privilegedGetOverridable(FACTORIES_FILTER_PROPNAME);
+        return propVal != null ? propVal : DEFAULT_SP_VALUE;
+    }
+}
--- a/src/share/classes/com/sun/naming/internal/VersionHelper.java	Sat Mar 27 19:01:26 2021 +0000
+++ b/src/share/classes/com/sun/naming/internal/VersionHelper.java	Wed Apr 07 05:55:34 2021 +0100
@@ -77,6 +77,9 @@
         return helper;
     }
 
+    public abstract Class<?> loadClassWithoutInit(String className)
+        throws ClassNotFoundException;
+
     public abstract Class<?> loadClass(String className)
         throws ClassNotFoundException;
 
--- a/src/share/classes/com/sun/naming/internal/VersionHelper12.java	Sat Mar 27 19:01:26 2021 +0000
+++ b/src/share/classes/com/sun/naming/internal/VersionHelper12.java	Wed Apr 07 05:55:34 2021 +0100
@@ -61,6 +61,10 @@
         return loadClass(className, getContextClassLoader());
     }
 
+    public Class<?> loadClassWithoutInit(String className) throws ClassNotFoundException {
+        return loadClass(className, false, getContextClassLoader());
+    }
+
     /**
      * Determines whether classes may be loaded from an arbitrary URL code base.
      */
@@ -86,10 +90,15 @@
      * This internal method is used with Thread Context Class Loader (TCCL),
      * please don't expose this method as public.
      */
+    Class<?> loadClass(String className, boolean initialize, ClassLoader cl)
+            throws ClassNotFoundException {
+        Class<?> cls = Class.forName(className, initialize, cl);
+        return cls;
+    }
+
     Class<?> loadClass(String className, ClassLoader cl)
         throws ClassNotFoundException {
-        Class<?> cls = Class.forName(className, true, cl);
-        return cls;
+        return loadClass(className, true, cl);
     }
 
     /**
--- a/src/share/classes/javax/naming/spi/NamingManager.java	Sat Mar 27 19:01:26 2021 +0000
+++ b/src/share/classes/javax/naming/spi/NamingManager.java	Wed Apr 07 05:55:34 2021 +0100
@@ -31,6 +31,8 @@
 import java.net.MalformedURLException;
 
 import javax.naming.*;
+
+import com.sun.naming.internal.ObjectFactoriesFilter;
 import com.sun.naming.internal.VersionHelper;
 import com.sun.naming.internal.ResourceManager;
 import com.sun.naming.internal.FactoryEnumeration;
@@ -143,7 +145,11 @@
 
         // Try to use current class loader
         try {
-             clas = helper.loadClass(factoryName);
+            clas = helper.loadClassWithoutInit(factoryName);
+            // Validate factory's class with the objects factory serial filter
+            if (!ObjectFactoriesFilter.canInstantiateObjectsFactory(clas)) {
+                return null;
+            }
         } catch (ClassNotFoundException e) {
             // ignore and continue
             // e.printStackTrace();
@@ -156,6 +162,11 @@
                 (codebase = ref.getFactoryClassLocation()) != null) {
             try {
                 clas = helper.loadClass(factoryName, codebase);
+                // Validate factory's class with the objects factory serial filter
+                if (clas == null ||
+                    !ObjectFactoriesFilter.canInstantiateObjectsFactory(clas)) {
+                    return null;
+                }
             } catch (ClassNotFoundException e) {
             }
         }
--- a/src/share/lib/security/java.security-aix	Sat Mar 27 19:01:26 2021 +0000
+++ b/src/share/lib/security/java.security-aix	Wed Apr 07 05:55:34 2021 +0100
@@ -1191,3 +1191,26 @@
 # System value prevails. The default value of the property is "false".
 #
 #jdk.security.allowNonCaAnchor=true
+
+#
+# JNDI Object Factories Filter
+#
+# This filter is used by the JNDI runtime to control the set of object factory classes
+# which will be allowed to instantiate objects from object references returned by
+# naming/directory systems. The factory class named by the reference instance will be
+# matched against this filter. The filter property supports pattern-based filter syntax
+# with the same format as jdk.serialFilter.
+#
+# Each pattern is matched against the factory class name to allow or disallow it's
+# instantiation. The access to a factory class is allowed unless the filter returns
+# REJECTED.
+#
+# Note: This property is currently used by the JDK Reference implementation.
+# It is not guaranteed to be examined and used by other implementations.
+#
+# If the system property jdk.jndi.object.factoriesFilter is also specified, it supersedes
+# the security property value defined here. The default value of the property is "*".
+#
+# The default pattern value allows any object factory class specified by the reference
+# instance to recreate the referenced object.
+#jdk.jndi.object.factoriesFilter=*
\ No newline at end of file
--- a/src/share/lib/security/java.security-linux	Sat Mar 27 19:01:26 2021 +0000
+++ b/src/share/lib/security/java.security-linux	Wed Apr 07 05:55:34 2021 +0100
@@ -1197,3 +1197,26 @@
 # System value prevails. The default value of the property is "false".
 #
 #jdk.security.allowNonCaAnchor=true
+
+#
+# JNDI Object Factories Filter
+#
+# This filter is used by the JNDI runtime to control the set of object factory classes
+# which will be allowed to instantiate objects from object references returned by
+# naming/directory systems. The factory class named by the reference instance will be
+# matched against this filter. The filter property supports pattern-based filter syntax
+# with the same format as jdk.serialFilter.
+#
+# Each pattern is matched against the factory class name to allow or disallow it's
+# instantiation. The access to a factory class is allowed unless the filter returns
+# REJECTED.
+#
+# Note: This property is currently used by the JDK Reference implementation.
+# It is not guaranteed to be examined and used by other implementations.
+#
+# If the system property jdk.jndi.object.factoriesFilter is also specified, it supersedes
+# the security property value defined here. The default value of the property is "*".
+#
+# The default pattern value allows any object factory class specified by the reference
+# instance to recreate the referenced object.
+#jdk.jndi.object.factoriesFilter=*
\ No newline at end of file
--- a/src/share/lib/security/java.security-macosx	Sat Mar 27 19:01:26 2021 +0000
+++ b/src/share/lib/security/java.security-macosx	Wed Apr 07 05:55:34 2021 +0100
@@ -1195,3 +1195,26 @@
 # System value prevails. The default value of the property is "false".
 #
 #jdk.security.allowNonCaAnchor=true
+
+#
+# JNDI Object Factories Filter
+#
+# This filter is used by the JNDI runtime to control the set of object factory classes
+# which will be allowed to instantiate objects from object references returned by
+# naming/directory systems. The factory class named by the reference instance will be
+# matched against this filter. The filter property supports pattern-based filter syntax
+# with the same format as jdk.serialFilter.
+#
+# Each pattern is matched against the factory class name to allow or disallow it's
+# instantiation. The access to a factory class is allowed unless the filter returns
+# REJECTED.
+#
+# Note: This property is currently used by the JDK Reference implementation.
+# It is not guaranteed to be examined and used by other implementations.
+#
+# If the system property jdk.jndi.object.factoriesFilter is also specified, it supersedes
+# the security property value defined here. The default value of the property is "*".
+#
+# The default pattern value allows any object factory class specified by the reference
+# instance to recreate the referenced object.
+#jdk.jndi.object.factoriesFilter=*
\ No newline at end of file
--- a/src/share/lib/security/java.security-solaris	Sat Mar 27 19:01:26 2021 +0000
+++ b/src/share/lib/security/java.security-solaris	Wed Apr 07 05:55:34 2021 +0100
@@ -1193,3 +1193,26 @@
 # System value prevails. The default value of the property is "false".
 #
 #jdk.security.allowNonCaAnchor=true
+
+#
+# JNDI Object Factories Filter
+#
+# This filter is used by the JNDI runtime to control the set of object factory classes
+# which will be allowed to instantiate objects from object references returned by
+# naming/directory systems. The factory class named by the reference instance will be
+# matched against this filter. The filter property supports pattern-based filter syntax
+# with the same format as jdk.serialFilter.
+#
+# Each pattern is matched against the factory class name to allow or disallow it's
+# instantiation. The access to a factory class is allowed unless the filter returns
+# REJECTED.
+#
+# Note: This property is currently used by the JDK Reference implementation.
+# It is not guaranteed to be examined and used by other implementations.
+#
+# If the system property jdk.jndi.object.factoriesFilter is also specified, it supersedes
+# the security property value defined here. The default value of the property is "*".
+#
+# The default pattern value allows any object factory class specified by the reference
+# instance to recreate the referenced object.
+#jdk.jndi.object.factoriesFilter=*
\ No newline at end of file
--- a/src/share/lib/security/java.security-windows	Sat Mar 27 19:01:26 2021 +0000
+++ b/src/share/lib/security/java.security-windows	Wed Apr 07 05:55:34 2021 +0100
@@ -1195,3 +1195,26 @@
 # System value prevails. The default value of the property is "false".
 #
 #jdk.security.allowNonCaAnchor=true
+
+#
+# JNDI Object Factories Filter
+#
+# This filter is used by the JNDI runtime to control the set of object factory classes
+# which will be allowed to instantiate objects from object references returned by
+# naming/directory systems. The factory class named by the reference instance will be
+# matched against this filter. The filter property supports pattern-based filter syntax
+# with the same format as jdk.serialFilter.
+#
+# Each pattern is matched against the factory class name to allow or disallow it's
+# instantiation. The access to a factory class is allowed unless the filter returns
+# REJECTED.
+#
+# Note: This property is currently used by the JDK Reference implementation.
+# It is not guaranteed to be examined and used by other implementations.
+#
+# If the system property jdk.jndi.object.factoriesFilter is also specified, it supersedes
+# the security property value defined here. The default value of the property is "*".
+#
+# The default pattern value allows any object factory class specified by the reference
+# instance to recreate the referenced object.
+#jdk.jndi.object.factoriesFilter=*
\ No newline at end of file