Den 2016-11-23 kl. 17:52, skrev Emmanuel Bourg:
> Would you be able to rebuild with this version of the
> ResourceLinkFactory class and see if it works better?
> 
> https://raw.githubusercontent.com/apache/tomcat70/TOMCAT_7_0_73/java/org/apache/naming/factory/ResourceLinkFactory.java
> 

Indeed, with this file, things seem to work (crossing my fingers that I
have understood how to use quilt, and thus built correctly). I had to
make one change to line 43 to make it compile.

I am attaching the refreshed version of CVE-2016-6797.patch for reference.

Merci beaucoup,
Arne


Description: Fixes CVE-2016-6797: The ResourceLinkFactory did not limit web
 application access to global JNDI resources to those resources explicitly
 linked to the web application. Therefore, it was possible for a web
 application to access any global JNDI resource whether an explicit
 ResourceLink had been configured or not.
Origin: backport, https://svn.apache.org/r1757275
--- a/java/org/apache/catalina/core/NamingContextListener.java
+++ b/java/org/apache/catalina/core/NamingContextListener.java
@@ -41,6 +41,7 @@
 import org.apache.catalina.ContainerEvent;
 import org.apache.catalina.ContainerListener;
 import org.apache.catalina.Context;
+import org.apache.catalina.Engine;
 import org.apache.catalina.Host;
 import org.apache.catalina.Lifecycle;
 import org.apache.catalina.LifecycleEvent;
@@ -68,6 +69,7 @@
 import org.apache.naming.ResourceRef;
 import org.apache.naming.ServiceRef;
 import org.apache.naming.TransactionRef;
+import org.apache.naming.factory.ResourceLinkFactory;
 import org.apache.tomcat.util.modeler.Registry;
 import org.apache.tomcat.util.res.StringManager;
 
@@ -344,6 +346,11 @@
                         registry.unregisterComponent(objectName);
                     }
                 }
+
+                javax.naming.Context global = getGlobalNamingContext();
+                if (global != null) {
+                    ResourceLinkFactory.deregisterGlobalResourceAccess(global);
+                }
             } finally {
                 objectNames.clear();
 
@@ -1167,6 +1174,17 @@
             logger.error(sm.getString("naming.bindFailed", e));
         }
 
+        ResourceLinkFactory.registerGlobalResourceAccess(
+                getGlobalNamingContext(), resourceLink.getName(), resourceLink.getGlobal());
+    }
+
+
+    private javax.naming.Context getGlobalNamingContext() {
+        if (container instanceof Context) {
+            Engine e = (Engine) ((Context) container).getParent().getParent();
+            return e.getService().getServer().getGlobalNamingContext();
+        }
+        return null;
     }
 
 
@@ -1270,6 +1288,7 @@
             logger.error(sm.getString("naming.unbindFailed", e));
         }
 
+        ResourceLinkFactory.deregisterGlobalResourceAccess(getGlobalNamingContext(), name);
     }
 
 
--- a/java/org/apache/naming/factory/ResourceLinkFactory.java
+++ b/java/org/apache/naming/factory/ResourceLinkFactory.java
@@ -5,20 +5,21 @@
  * The ASF licenses this file to You under the Apache License, Version 2.0
  * (the "License"); you may not use this file except in compliance with
  * the License.  You may obtain a copy of the License at
- * 
+ *
  *      http://www.apache.org/licenses/LICENSE-2.0
- * 
+ *
  * Unless required by applicable law or agreed to in writing, software
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
- */ 
-
-
+ */
 package org.apache.naming.factory;
 
+import java.util.HashMap;
 import java.util.Hashtable;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
 
 import javax.naming.Context;
 import javax.naming.Name;
@@ -28,35 +29,32 @@
 import javax.naming.spi.ObjectFactory;
 
 import org.apache.naming.ResourceLinkRef;
-
+import org.apache.naming.StringManager;
 
 /**
  * <p>Object factory for resource links.</p>
- * 
+ *
  * @author Remy Maucherat
  */
-public class ResourceLinkFactory
-    implements ObjectFactory {
-
-
-    // ----------------------------------------------------------- Constructors
-
+public class ResourceLinkFactory implements ObjectFactory {
 
     // ------------------------------------------------------- Static Variables
 
+    private static final StringManager sm = StringManager.getManager(Constants.Package);
 
     /**
      * Global naming context.
      */
     private static Context globalContext = null;
 
+    private static Map<ClassLoader,Map<String,String>> globalResourceRegistrations =
+            new ConcurrentHashMap<ClassLoader,Map<String,String>>();
 
     // --------------------------------------------------------- Public Methods
 
-
     /**
      * Set the global context (note: can only be used once).
-     * 
+     *
      * @param newGlobalContext new global context value
      */
     public static void setGlobalContext(Context newGlobalContext) {
@@ -69,21 +67,73 @@
     }
 
 
-    // -------------------------------------------------- ObjectFactory Methods
+    public static void registerGlobalResourceAccess(Context globalContext, String localName,
+            String globalName) {
+        validateGlobalContext(globalContext);
+        ClassLoader cl = Thread.currentThread().getContextClassLoader();
+        Map<String,String> registrations = globalResourceRegistrations.get(cl);
+        if (registrations == null) {
+            // Web application initialization is single threaded so this is
+            // safe.
+            registrations = new HashMap<String,String>();
+            globalResourceRegistrations.put(cl, registrations);
+        }
+        registrations.put(localName, globalName);
+    }
+
+
+    public static void deregisterGlobalResourceAccess(Context globalContext, String localName) {
+        validateGlobalContext(globalContext);
+        ClassLoader cl = Thread.currentThread().getContextClassLoader();
+        Map<String,String> registrations = globalResourceRegistrations.get(cl);
+        if (registrations != null) {
+            registrations.remove(localName);
+        }
+    }
 
 
+    public static void deregisterGlobalResourceAccess(Context globalContext) {
+        validateGlobalContext(globalContext);
+        ClassLoader cl = Thread.currentThread().getContextClassLoader();
+        globalResourceRegistrations.remove(cl);
+    }
+
+
+    private static void validateGlobalContext(Context globalContext) {
+        if (ResourceLinkFactory.globalContext != null &&
+                ResourceLinkFactory.globalContext != globalContext) {
+            throw new SecurityException("Caller provided invalid global context");
+        }
+    }
+
+
+    private static boolean validateGlobalResourceAccess(String globalName) {
+        ClassLoader cl = Thread.currentThread().getContextClassLoader();
+        while (cl != null) {
+            Map<String,String> registrations = globalResourceRegistrations.get(cl);
+            if (registrations != null && registrations.containsValue(globalName)) {
+                return true;
+            }
+            cl = cl.getParent();
+        }
+        return false;
+    }
+
+
+    // -------------------------------------------------- ObjectFactory Methods
+
     /**
      * Create a new DataSource instance.
-     * 
+     *
      * @param obj The reference object describing the DataSource
      */
     @Override
     public Object getObjectInstance(Object obj, Name name, Context nameCtx,
-                                    Hashtable<?,?> environment)
-        throws NamingException {
-        
-        if (!(obj instanceof ResourceLinkRef))
+            Hashtable<?,?> environment) throws NamingException {
+
+        if (!(obj instanceof ResourceLinkRef)) {
             return null;
+        }
 
         // Can we process this request?
         Reference ref = (Reference) obj;
@@ -93,16 +143,33 @@
         RefAddr refAddr = ref.get(ResourceLinkRef.GLOBALNAME);
         if (refAddr != null) {
             globalName = refAddr.getContent().toString();
+            // Confirm that the current web application is currently configured
+            // to access the specified global resource
+            if (!validateGlobalResourceAccess(globalName)) {
+                return null;
+            }
             Object result = null;
             result = globalContext.lookup(globalName);
-            // FIXME: Check type
+            // Check the expected type
+            String expectedClassName = ref.getClassName();
+            if (expectedClassName == null) {
+                throw new IllegalArgumentException(
+                        sm.getString("resourceLinkFactory.nullType", name, globalName));
+            }
+            try {
+                Class<?> expectedClazz = Class.forName(
+                        expectedClassName, true, Thread.currentThread().getContextClassLoader());
+                if (!expectedClazz.isAssignableFrom(result.getClass())) {
+                    throw new IllegalArgumentException(sm.getString("resourceLinkFactory.wrongType",
+                            name, globalName, expectedClassName, result.getClass().getName()));
+                }
+            } catch (ClassNotFoundException e) {
+                throw new IllegalArgumentException(sm.getString("resourceLinkFactory.unknownType",
+                        name, globalName, expectedClassName), e);
+            }
             return result;
         }
 
-        return (null);
-
-        
+        return null;
     }
-
-
 }
--- /dev/null
+++ b/test/org/apache/naming/TestNamingContext.java
@@ -0,0 +1,87 @@
+package org.apache.naming;
+
+import javax.naming.Context;
+import javax.naming.NamingException;
+
+import org.apache.catalina.deploy.ContextEnvironment;
+import org.apache.catalina.deploy.ContextResourceLink;
+import org.apache.catalina.startup.Tomcat;
+import org.apache.catalina.startup.TomcatBaseTest;
+import org.apache.naming.factory.ResourceLinkFactory;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class TestNamingContext extends TomcatBaseTest {
+
+    private static final String COMP_ENV = "comp/env";
+    private static final String GLOBAL_NAME = "global";
+    private static final String LOCAL_NAME = "local";
+    private static final String DATA = "Cabbage";
+
+
+    @Test
+    public void testGlobalNaming() throws Exception {
+        Tomcat tomcat = getTomcatInstance();
+        tomcat.enableNaming();
+
+        org.apache.catalina.Context ctx = tomcat.addContext("", null);
+
+        tomcat.start();
+
+        Context webappInitial = ContextBindings.getContext(ctx);
+
+        // Nothing added at the moment so should be null
+        Object obj = doLookup(webappInitial, COMP_ENV + "/" + LOCAL_NAME);
+        Assert.assertNull(obj);
+
+        ContextEnvironment ce = new ContextEnvironment();
+        ce.setName(GLOBAL_NAME);
+        ce.setValue(DATA);
+        ce.setType(DATA.getClass().getName());
+
+        tomcat.getServer().getGlobalNamingResources().addEnvironment(ce);
+
+        // No link so still should be null
+        obj = doLookup(webappInitial, COMP_ENV + "/" + LOCAL_NAME);
+        Assert.assertNull(obj);
+
+        // Now add a resource link to the context
+        ContextResourceLink crl = new ContextResourceLink();
+        crl.setGlobal(GLOBAL_NAME);
+        crl.setName(LOCAL_NAME);
+        crl.setType(DATA.getClass().getName());
+        ctx.getNamingResources().addResourceLink(crl);
+
+        // Link exists so should be OK now
+        obj = doLookup(webappInitial, COMP_ENV + "/" + LOCAL_NAME);
+        Assert.assertEquals(DATA, obj);
+
+        // Try shortcut
+        ResourceLinkFactory factory = new ResourceLinkFactory();
+        ResourceLinkRef rlr = new ResourceLinkRef(DATA.getClass().getName(), GLOBAL_NAME, null, null);
+        obj = factory.getObjectInstance(rlr, null, null, null);
+        Assert.assertEquals(DATA, obj);
+
+        // Remove the link
+        ctx.getNamingResources().removeResourceLink(LOCAL_NAME);
+
+        // No link so should be null
+        obj = doLookup(webappInitial, COMP_ENV + "/" + LOCAL_NAME);
+        Assert.assertNull(obj);
+
+        // Shortcut should fail too
+        obj = factory.getObjectInstance(rlr, null, null, null);
+        Assert.assertNull(obj);
+    }
+
+
+    private Object doLookup(Context context, String name) {
+        Object result = null;
+        try {
+            result = context.lookup(name);
+        } catch (NamingException nnfe) {
+            // Ignore
+        }
+        return result;
+    }
+}

Reply via email to