VYPR
High severity7.5NVD Advisory· Published Aug 10, 2017· Updated May 13, 2026

CVE-2016-6797

CVE-2016-6797

Description

The ResourceLinkFactory implementation in Apache Tomcat 9.0.0.M1 to 9.0.0.M9, 8.5.0 to 8.5.4, 8.0.0.RC1 to 8.0.36, 7.0.0 to 7.0.70 and 6.0.0 to 6.0.45 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.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
org.apache.tomcat:tomcatMaven
>= 9.0.0.M1, < 9.0.0.M109.0.0.M10
org.apache.tomcat:tomcatMaven
>= 8.5.0, < 8.5.58.5.5
org.apache.tomcat:tomcatMaven
>= 8.0.0, < 8.0.378.0.37
org.apache.tomcat:tomcatMaven
>= 7.0.0, < 7.0.727.0.72

Affected products

30
  • Apache Software Foundation/Apache Tomcatv5
    Range: 9.0.0.M1 to 9.0.0.M9
  • cpe:2.3:a:oracle:tekelec_platform_distribution:*:*:*:*:*:*:*:*
    Range: >=7.4.0,<=7.7.1
  • cpe:2.3:o:debian:debian_linux:8.0:*:*:*:*:*:*:*
  • cpe:2.3:a:netapp:oncommand_insight:-:*:*:*:*:*:*:*
  • cpe:2.3:a:netapp:oncommand_shift:-:*:*:*:*:*:*:*
  • cpe:2.3:a:netapp:snap_creator_framework:-:*:*:*:*:*:*:*
  • cpe:2.3:o:canonical:ubuntu_linux:16.04:*:*:*:esm:*:*:*
  • cpe:2.3:a:redhat:jboss_enterprise_web_server:3.0.0:*:*:*:*:*:*:*
  • cpe:2.3:o:redhat:enterprise_linux_eus:7.6:*:*:*:*:*:*:*+ 3 more
    • cpe:2.3:o:redhat:enterprise_linux_eus:7.6:*:*:*:*:*:*:*
    • cpe:2.3:o:redhat:enterprise_linux_eus:7.7:*:*:*:*:*:*:*
    • cpe:2.3:o:redhat:enterprise_linux_eus:7.4:*:*:*:*:*:*:*
    • cpe:2.3:o:redhat:enterprise_linux_eus:7.5:*:*:*:*:*:*:*
  • cpe:2.3:o:redhat:enterprise_linux_server:7.0:*:*:*:*:*:*:*
  • cpe:2.3:o:redhat:enterprise_linux_server_aus:7.4:*:*:*:*:*:*:*+ 2 more
    • cpe:2.3:o:redhat:enterprise_linux_server_aus:7.4:*:*:*:*:*:*:*
    • cpe:2.3:o:redhat:enterprise_linux_server_aus:7.6:*:*:*:*:*:*:*
    • cpe:2.3:o:redhat:enterprise_linux_server_aus:7.7:*:*:*:*:*:*:*
  • cpe:2.3:o:redhat:enterprise_linux_server_tus:7.6:*:*:*:*:*:*:*+ 1 more
    • cpe:2.3:o:redhat:enterprise_linux_server_tus:7.6:*:*:*:*:*:*:*
    • cpe:2.3:o:redhat:enterprise_linux_server_tus:7.7:*:*:*:*:*:*:*
  • cpe:2.3:o:redhat:enterprise_linux_workstation:7.0:*:*:*:*:*:*:*
  • Apache/Tomcat10 versions
    cpe:2.3:a:apache:tomcat:*:*:*:*:*:*:*:*+ 9 more
    • cpe:2.3:a:apache:tomcat:*:*:*:*:*:*:*:*range: >=6.0.0,<=6.0.45
    • cpe:2.3:a:apache:tomcat:9.0.0:milestone1:*:*:*:*:*:*
    • cpe:2.3:a:apache:tomcat:9.0.0:milestone2:*:*:*:*:*:*
    • cpe:2.3:a:apache:tomcat:9.0.0:milestone3:*:*:*:*:*:*
    • cpe:2.3:a:apache:tomcat:9.0.0:milestone4:*:*:*:*:*:*
    • cpe:2.3:a:apache:tomcat:9.0.0:milestone5:*:*:*:*:*:*
    • cpe:2.3:a:apache:tomcat:9.0.0:milestone6:*:*:*:*:*:*
    • cpe:2.3:a:apache:tomcat:9.0.0:milestone7:*:*:*:*:*:*
    • cpe:2.3:a:apache:tomcat:9.0.0:milestone8:*:*:*:*:*:*
    • cpe:2.3:a:apache:tomcat:9.0.0:milestone9:*:*:*:*:*:*
  • cpe:2.3:o:redhat:enterprise_linux_desktop:7.0:*:*:*:*:*:*:*

Patches

4
b3406e6c3183

When adding and removing ResourceLinks dynamically, ensure that the global resource is only visible via the ResourceLinkFactory when it is meant to be.

https://github.com/apache/tomcatMark ThomasAug 22, 2016via ghsa
4 files changed · +218 46
  • java/org/apache/catalina/core/NamingContextListener.java+58 39 modified
    @@ -5,9 +5,9 @@
      * 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.
    @@ -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;
     
    @@ -88,8 +90,8 @@ public class NamingContextListener
     
     
         protected Log logger = log;
    -    
    -    
    +
    +
         /**
          * Name of the associated naming context.
          */
    @@ -131,13 +133,13 @@ public class NamingContextListener
          */
         protected javax.naming.Context envCtx = null;
     
    -    
    +
         /**
          * Objectnames hashtable.
          */
         protected HashMap<String, ObjectName> objectNames =
             new HashMap<String, ObjectName>();
    -    
    +
     
         /**
          * Determines if an attempt to write to a read-only context results in an
    @@ -192,23 +194,23 @@ public void setName(String name) {
             this.name = name;
         }
     
    -    
    +
         /**
          * Return the comp context.
          */
         @Deprecated
         public javax.naming.Context getCompContext() {
             return this.compCtx;
         }
    -    
    +
     
         /**
          * Return the env context.
          */
         public javax.naming.Context getEnvContext() {
             return this.envCtx;
         }
    -    
    +
     
         /**
          * Return the associated naming context.
    @@ -282,7 +284,7 @@ public void lifecycleEvent(LifecycleEvent event) {
                         ContextAccessController.setReadOnly(getName());
                         try {
                             ContextBindings.bindClassLoader
    -                        (container, container, 
    +                        (container, container,
                                     ((Container) container).getLoader().getClassLoader());
                         } catch (NamingException e) {
                             logger.error(sm.getString("naming.bindFailed", e));
    @@ -294,7 +296,7 @@ public void lifecycleEvent(LifecycleEvent event) {
                         (namingContext);
                         try {
                             ContextBindings.bindClassLoader
    -                        (container, container, 
    +                        (container, container,
                                     this.getClass().getClassLoader());
                         } catch (NamingException e) {
                             logger.error(sm.getString("naming.bindFailed", e));
    @@ -322,14 +324,14 @@ public void lifecycleEvent(LifecycleEvent event) {
     
                     if (container instanceof Context) {
                         ContextBindings.unbindClassLoader
    -                    (container, container, 
    +                    (container, container,
                                 ((Container) container).getLoader().getClassLoader());
                     }
     
                     if (container instanceof Server) {
                         namingResources.removePropertyChangeListener(this);
                         ContextBindings.unbindClassLoader
    -                    (container, container, 
    +                    (container, container,
                                 this.getClass().getClassLoader());
                     }
     
    @@ -344,6 +346,11 @@ public void lifecycleEvent(LifecycleEvent event) {
                             registry.unregisterComponent(objectName);
                         }
                     }
    +
    +                javax.naming.Context global = getGlobalNamingContext();
    +                if (global != null) {
    +                    ResourceLinkFactory.deregisterGlobalResourceAccess(global);
    +                }
                 } finally {
                     objectNames.clear();
     
    @@ -391,7 +398,7 @@ public void containerEvent(ContainerEvent event) {
     
                 String environmentName = (String) event.getData();
                 if (environmentName != null) {
    -                ContextEnvironment env = 
    +                ContextEnvironment env =
                         namingResources.findEnvironment(environmentName);
                     addEnvironment(env);
                 }
    @@ -400,7 +407,7 @@ public void containerEvent(ContainerEvent event) {
     
                 String localEjbName = (String) event.getData();
                 if (localEjbName != null) {
    -                ContextLocalEjb localEjb = 
    +                ContextLocalEjb localEjb =
                         namingResources.findLocalEjb(localEjbName);
                     addLocalEjb(localEjb);
                 }
    @@ -409,7 +416,7 @@ public void containerEvent(ContainerEvent event) {
     
                 String resourceName = (String) event.getData();
                 if (resourceName != null) {
    -                ContextResource resource = 
    +                ContextResource resource =
                         namingResources.findResource(resourceName);
                     addResource(resource);
                 }
    @@ -418,7 +425,7 @@ public void containerEvent(ContainerEvent event) {
     
                 String resourceLinkName = (String) event.getData();
                 if (resourceLinkName != null) {
    -                ContextResourceLink resourceLink = 
    +                ContextResourceLink resourceLink =
                         namingResources.findResourceLink(resourceLinkName);
                     addResourceLink(resourceLink);
                 }
    @@ -427,7 +434,7 @@ public void containerEvent(ContainerEvent event) {
     
                 String resourceEnvRefName = (String) event.getData();
                 if (resourceEnvRefName != null) {
    -                ContextResourceEnvRef resourceEnvRef = 
    +                ContextResourceEnvRef resourceEnvRef =
                         namingResources.findResourceEnvRef(resourceEnvRefName);
                     addResourceEnvRef(resourceEnvRef);
                 }
    @@ -436,7 +443,7 @@ public void containerEvent(ContainerEvent event) {
     
                 String serviceName = (String) event.getData();
                 if (serviceName != null) {
    -                ContextService service = 
    +                ContextService service =
                         namingResources.findService(serviceName);
                     addService(service);
                 }
    @@ -599,14 +606,14 @@ private void processGlobalResourcesChange(String name,
                 }
             } else if (name.equals("resourceEnvRef")) {
                 if (oldValue != null) {
    -                ContextResourceEnvRef resourceEnvRef = 
    +                ContextResourceEnvRef resourceEnvRef =
                         (ContextResourceEnvRef) oldValue;
                     if (resourceEnvRef.getName() != null) {
                         removeResourceEnvRef(resourceEnvRef.getName());
                     }
                 }
                 if (newValue != null) {
    -                ContextResourceEnvRef resourceEnvRef = 
    +                ContextResourceEnvRef resourceEnvRef =
                         (ContextResourceEnvRef) newValue;
                     if (resourceEnvRef.getName() != null) {
                         addResourceEnvRef(resourceEnvRef);
    @@ -670,7 +677,7 @@ private void createNamingContext()
             }
     
             // Resource links
    -        ContextResourceLink[] resourceLinks = 
    +        ContextResourceLink[] resourceLinks =
                 namingResources.findResourceLinks();
             for (i = 0; i < resourceLinks.length; i++) {
                 addResourceLink(resourceLinks[i]);
    @@ -689,7 +696,7 @@ private void createNamingContext()
             }
     
             // Environment entries
    -        ContextEnvironment[] contextEnvironments = 
    +        ContextEnvironment[] contextEnvironments =
                 namingResources.findEnvironments();
             for (i = 0; i < contextEnvironments.length; i++) {
                 addEnvironment(contextEnvironments[i]);
    @@ -723,7 +730,7 @@ private void createNamingContext()
                         }
                     }
                 } catch (NameAlreadyBoundException e) {
    -                // Ignore because UserTransaction was obviously 
    +                // Ignore because UserTransaction was obviously
                     // added via ResourceLink
                 } catch (NamingException e) {
                     logger.error(sm.getString("naming.bindFailed", e));
    @@ -733,7 +740,7 @@ private void createNamingContext()
             // Binding the resources directory context
             if (container instanceof Context) {
                 try {
    -                compCtx.bind("Resources", 
    +                compCtx.bind("Resources",
                                  ((Container) container).getResources());
                 } catch (NamingException e) {
                     logger.error(sm.getString("naming.bindFailed", e));
    @@ -763,30 +770,30 @@ protected ObjectName createObjectName(ContextResource resource)
             if (domain == null) {
                 domain = "Catalina";
             }
    -        
    +
             ObjectName name = null;
             String quotedResourceName = ObjectName.quote(resource.getName());
    -        if (container instanceof Server) {        
    +        if (container instanceof Server) {
                 name = new ObjectName(domain + ":type=DataSource" +
    -                        ",class=" + resource.getType() + 
    +                        ",class=" + resource.getType() +
                             ",name=" + quotedResourceName);
    -        } else if (container instanceof Context) {                    
    +        } else if (container instanceof Context) {
                 String contextName = ((Context)container).getName();
                 if (!contextName.startsWith("/"))
                     contextName = "/" + contextName;
                 Host host = (Host) ((Context)container).getParent();
                 name = new ObjectName(domain + ":type=DataSource" +
    -                        ",context=" + contextName + 
    +                        ",context=" + contextName +
                             ",host=" + host.getName() +
                             ",class=" + resource.getType() +
                             ",name=" + quotedResourceName);
             }
    -        
    +
             return (name);
     
         }
     
    -    
    +
         /**
          * Set the specified EJBs in the naming context.
          */
    @@ -964,7 +971,7 @@ public void addService(ContextService service) {
                         wsdlURL = ((Context) container).
                                                         getServletContext().
                                                         getResource("/" + service.getWsdlfile());
    -                    logger.debug("  Changing service ref wsdl file for /" 
    +                    logger.debug("  Changing service ref wsdl file for /"
                                     + service.getWsdlfile());
                     } catch (MalformedURLException e) {
                         logger.error(sm.getString("naming.wsdlFailed", e));
    @@ -998,7 +1005,7 @@ public void addService(ContextService service) {
                         jaxrpcURL = ((Context) container).
                                                         getServletContext().
                                                         getResource("/" + service.getJaxrpcmappingfile());
    -                    logger.debug("  Changing service ref jaxrpc file for /" 
    +                    logger.debug("  Changing service ref jaxrpc file for /"
                                     + service.getJaxrpcmappingfile());
                     } catch (MalformedURLException e) {
                         logger.error(sm.getString("naming.wsdlFailed", e));
    @@ -1055,7 +1062,7 @@ public void addService(ContextService service) {
     
             try {
                 if (logger.isDebugEnabled()) {
    -                logger.debug("  Adding service ref " 
    +                logger.debug("  Adding service ref "
                                  + service.getName() + "  " + ref);
                 }
                 createSubcontexts(envCtx, service.getName());
    @@ -1087,7 +1094,7 @@ public void addResource(ContextResource resource) {
             }
             try {
                 if (logger.isDebugEnabled()) {
    -                logger.debug("  Adding resource ref " 
    +                logger.debug("  Adding resource ref "
                                  + resource.getName() + "  " + ref);
                 }
                 createSubcontexts(envCtx, resource.getName());
    @@ -1107,7 +1114,7 @@ public void addResource(ContextResource resource) {
                     logger.warn(sm.getString("naming.jmxRegistrationFailed", e));
                 }
             }
    -        
    +
         }
     
     
    @@ -1155,8 +1162,8 @@ public void addResourceLink(ContextResourceLink resourceLink) {
                     ref.add(refAddr);
                 }
             }
    -        javax.naming.Context ctx = 
    -            "UserTransaction".equals(resourceLink.getName()) 
    +        javax.naming.Context ctx =
    +            "UserTransaction".equals(resourceLink.getName())
                 ? compCtx : envCtx;
             try {
                 if (logger.isDebugEnabled())
    @@ -1167,6 +1174,17 @@ public void addResourceLink(ContextResourceLink resourceLink) {
                 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 @@ public void removeResourceLink(String name) {
                 logger.error(sm.getString("naming.unbindFailed", e));
             }
     
    +        ResourceLinkFactory.deregisterGlobalResourceAccess(getGlobalNamingContext(), name);
         }
     
     
    
  • java/org/apache/naming/factory/ResourceLinkFactory.java+68 7 modified
    @@ -5,18 +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;
    @@ -29,7 +32,7 @@
     
     /**
      * <p>Object factory for resource links.</p>
    - * 
    + *
      * @author Remy Maucherat
      */
     public class ResourceLinkFactory implements ObjectFactory {
    @@ -41,12 +44,14 @@ public class ResourceLinkFactory implements ObjectFactory {
          */
         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) {
    @@ -59,17 +64,67 @@ public static void setGlobalContext(Context newGlobalContext) {
         }
     
     
    +    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();
    +        Map<String,String> registrations = globalResourceRegistrations.get(cl);
    +        if (registrations != null && registrations.containsValue(globalName)) {
    +            return true;
    +        }
    +        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)) {
                 return null;
             }
    @@ -82,6 +137,12 @@ public Object getObjectInstance(Object obj, Name name, Context nameCtx,
             RefAddr refAddr = ref.get(ResourceLinkRef.GLOBALNAME);
             if (refAddr != null) {
                 globalName = refAddr.getContent().toString();
    +            // When running under a security manager confirm that the current
    +            // web application has really been configured to access the specified
    +            // global resource
    +            if (!validateGlobalResourceAccess(globalName)) {
    +                return null;
    +            }
                 Object result = null;
                 result = globalContext.lookup(globalName);
                 // Check the expected type
    
  • test/org/apache/naming/TestNamingContext.java+87 0 added
    @@ -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;
    +    }
    +}
    
  • webapps/docs/changelog.xml+5 0 modified
    @@ -137,6 +137,11 @@
             >CVE-2016-5388</a>) by default and to provide a mechanism that can be
             used to mitigate any future, similar issues. (markt)
           </add>
    +      <add>
    +        When adding and removing <code>ResourceLink</code>s dynamically, ensure
    +        that the global resource is only visible via the
    +        <code>ResourceLinkFactory</code> when it is meant to be. (markt)
    +      </add>
         </changelog>
       </subsection>
       <subsection name="Coyote">
    
824c7dc78105

When adding and removing ResourceLinks dynamically, ensure that the global resource is only visible via the ResourceLinkFactory when it is meant to be.

https://github.com/apache/tomcat80Mark ThomasAug 22, 2016via ghsa
4 files changed · +172 0
  • java/org/apache/catalina/core/NamingContextListener.java+19 0 modified
    @@ -40,6 +40,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;
    @@ -58,6 +59,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.descriptor.web.ContextEjb;
     import org.apache.tomcat.util.descriptor.web.ContextEnvironment;
     import org.apache.tomcat.util.descriptor.web.ContextHandler;
    @@ -325,6 +327,11 @@ public void lifecycleEvent(LifecycleEvent event) {
                             registry.unregisterComponent(objectName);
                         }
                     }
    +
    +                javax.naming.Context global = getGlobalNamingContext();
    +                if (global != null) {
    +                    ResourceLinkFactory.deregisterGlobalResourceAccess(global);
    +                }
                 } finally {
                     objectNames.clear();
     
    @@ -1148,6 +1155,17 @@ public void addResourceLink(ContextResourceLink resourceLink) {
                 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;
         }
     
     
    @@ -1251,6 +1269,7 @@ public void removeResourceLink(String name) {
                 logger.error(sm.getString("naming.unbindFailed", e));
             }
     
    +        ResourceLinkFactory.deregisterGlobalResourceAccess(getGlobalNamingContext(), name);
         }
     
     
    
  • java/org/apache/naming/factory/ResourceLinkFactory.java+61 0 modified
    @@ -16,7 +16,10 @@
      */
     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;
    @@ -41,6 +44,8 @@ public class ResourceLinkFactory implements ObjectFactory {
          */
         private static Context globalContext = null;
     
    +    private static Map<ClassLoader,Map<String,String>> globalResourceRegistrations =
    +            new ConcurrentHashMap<>();
     
         // --------------------------------------------------------- Public Methods
     
    @@ -59,6 +64,56 @@ public static void setGlobalContext(Context newGlobalContext) {
         }
     
     
    +    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<>();
    +            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();
    +        Map<String,String> registrations = globalResourceRegistrations.get(cl);
    +        if (registrations != null && registrations.containsValue(globalName)) {
    +            return true;
    +        }
    +        return false;
    +    }
    +
    +
         // -------------------------------------------------- ObjectFactory Methods
     
         /**
    @@ -82,6 +137,12 @@ public Object getObjectInstance(Object obj, Name name, Context nameCtx,
             RefAddr refAddr = ref.get(ResourceLinkRef.GLOBALNAME);
             if (refAddr != null) {
                 globalName = refAddr.getContent().toString();
    +            // When running under a security manager confirm that the current
    +            // web application has really been configured to access the specified
    +            // global resource
    +            if (!validateGlobalResourceAccess(globalName)) {
    +                return null;
    +            }
                 Object result = null;
                 result = globalContext.lookup(globalName);
                 // Check the expected type
    
  • test/org/apache/naming/TestNamingContext.java+87 0 added
    @@ -0,0 +1,87 @@
    +package org.apache.naming;
    +
    +import javax.naming.Context;
    +import javax.naming.NamingException;
    +
    +import org.apache.catalina.startup.Tomcat;
    +import org.apache.catalina.startup.TomcatBaseTest;
    +import org.apache.naming.factory.ResourceLinkFactory;
    +import org.apache.tomcat.util.descriptor.web.ContextEnvironment;
    +import org.apache.tomcat.util.descriptor.web.ContextResourceLink;
    +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;
    +    }
    +}
    
  • webapps/docs/changelog.xml+5 0 modified
    @@ -170,6 +170,11 @@
             >CVE-2016-5388</a>) by default and to provide a mechanism that can be
             used to mitigate any future, similar issues. (markt)
           </add>
    +      <add>
    +        When adding and removing <code>ResourceLink</code>s dynamically, ensure
    +        that the global resource is only visible via the
    +        <code>ResourceLinkFactory</code> when it is meant to be. (markt)
    +      </add>
         </changelog>
       </subsection>
       <subsection name="Coyote">
    
d6b5600afe75

When adding and removing ResourceLinks dynamically, ensure that the global resource is only visible via the ResourceLinkFactory when it is meant to be.

https://github.com/apache/tomcatMark ThomasAug 22, 2016via ghsa
4 files changed · +172 0
  • java/org/apache/catalina/core/NamingContextListener.java+19 0 modified
    @@ -40,6 +40,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;
    @@ -58,6 +59,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.descriptor.web.ContextEjb;
     import org.apache.tomcat.util.descriptor.web.ContextEnvironment;
     import org.apache.tomcat.util.descriptor.web.ContextHandler;
    @@ -316,6 +318,11 @@ public void lifecycleEvent(LifecycleEvent event) {
                             registry.unregisterComponent(objectName);
                         }
                     }
    +
    +                javax.naming.Context global = getGlobalNamingContext();
    +                if (global != null) {
    +                    ResourceLinkFactory.deregisterGlobalResourceAccess(global);
    +                }
                 } finally {
                     objectNames.clear();
     
    @@ -1152,6 +1159,17 @@ public void addResourceLink(ContextResourceLink resourceLink) {
                 log.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;
         }
     
     
    @@ -1269,6 +1287,7 @@ public void removeResourceLink(String name) {
                 log.error(sm.getString("naming.unbindFailed", e));
             }
     
    +        ResourceLinkFactory.deregisterGlobalResourceAccess(getGlobalNamingContext(), name);
         }
     
     
    
  • java/org/apache/naming/factory/ResourceLinkFactory.java+61 0 modified
    @@ -16,7 +16,10 @@
      */
     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;
    @@ -41,6 +44,8 @@ public class ResourceLinkFactory implements ObjectFactory {
          */
         private static Context globalContext = null;
     
    +    private static Map<ClassLoader,Map<String,String>> globalResourceRegistrations =
    +            new ConcurrentHashMap<>();
     
         // --------------------------------------------------------- Public Methods
     
    @@ -59,6 +64,56 @@ public static void setGlobalContext(Context newGlobalContext) {
         }
     
     
    +    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<>();
    +            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();
    +        Map<String,String> registrations = globalResourceRegistrations.get(cl);
    +        if (registrations != null && registrations.containsValue(globalName)) {
    +            return true;
    +        }
    +        return false;
    +    }
    +
    +
         // -------------------------------------------------- ObjectFactory Methods
     
         /**
    @@ -82,6 +137,12 @@ public Object getObjectInstance(Object obj, Name name, Context nameCtx,
             RefAddr refAddr = ref.get(ResourceLinkRef.GLOBALNAME);
             if (refAddr != null) {
                 globalName = refAddr.getContent().toString();
    +            // When running under a security manager confirm that the current
    +            // web application has really been configured to access the specified
    +            // global resource
    +            if (!validateGlobalResourceAccess(globalName)) {
    +                return null;
    +            }
                 Object result = null;
                 result = globalContext.lookup(globalName);
                 // Check the expected type
    
  • test/org/apache/naming/TestNamingContext.java+87 0 added
    @@ -0,0 +1,87 @@
    +package org.apache.naming;
    +
    +import javax.naming.Context;
    +import javax.naming.NamingException;
    +
    +import org.apache.catalina.startup.Tomcat;
    +import org.apache.catalina.startup.TomcatBaseTest;
    +import org.apache.naming.factory.ResourceLinkFactory;
    +import org.apache.tomcat.util.descriptor.web.ContextEnvironment;
    +import org.apache.tomcat.util.descriptor.web.ContextResourceLink;
    +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;
    +    }
    +}
    
  • webapps/docs/changelog.xml+5 0 modified
    @@ -153,6 +153,11 @@
             >CVE-2016-5388</a>) by default and to provide a mechanism that can be
             used to mitigate any future, similar issues. (markt)
           </add>
    +      <add>
    +        When adding and removing <code>ResourceLink</code>s dynamically, ensure
    +        that the global resource is only visible via the
    +        <code>ResourceLinkFactory</code> when it is meant to be. (markt)
    +      </add>
         </changelog>
       </subsection>
       <subsection name="Coyote">
    
2859ac3eae13

When adding and removing ResourceLinks dynamically, ensure

https://github.com/apache/tomcatMark ThomasAug 22, 2016via ghsa
4 files changed · +172 0
  • java/org/apache/catalina/core/NamingContextListener.java+19 0 modified
    @@ -40,6 +40,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;
    @@ -58,6 +59,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.descriptor.web.ContextEjb;
     import org.apache.tomcat.util.descriptor.web.ContextEnvironment;
     import org.apache.tomcat.util.descriptor.web.ContextHandler;
    @@ -316,6 +318,11 @@ public void lifecycleEvent(LifecycleEvent event) {
                             registry.unregisterComponent(objectName);
                         }
                     }
    +
    +                javax.naming.Context global = getGlobalNamingContext();
    +                if (global != null) {
    +                    ResourceLinkFactory.deregisterGlobalResourceAccess(global);
    +                }
                 } finally {
                     objectNames.clear();
     
    @@ -1152,6 +1159,17 @@ public void addResourceLink(ContextResourceLink resourceLink) {
                 log.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;
         }
     
     
    @@ -1269,6 +1287,7 @@ public void removeResourceLink(String name) {
                 log.error(sm.getString("naming.unbindFailed", e));
             }
     
    +        ResourceLinkFactory.deregisterGlobalResourceAccess(getGlobalNamingContext(), name);
         }
     
     
    
  • java/org/apache/naming/factory/ResourceLinkFactory.java+61 0 modified
    @@ -16,7 +16,10 @@
      */
     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;
    @@ -41,6 +44,8 @@ public class ResourceLinkFactory implements ObjectFactory {
          */
         private static Context globalContext = null;
     
    +    private static Map<ClassLoader,Map<String,String>> globalResourceRegistrations =
    +            new ConcurrentHashMap<>();
     
         // --------------------------------------------------------- Public Methods
     
    @@ -59,6 +64,56 @@ public static void setGlobalContext(Context newGlobalContext) {
         }
     
     
    +    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<>();
    +            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();
    +        Map<String,String> registrations = globalResourceRegistrations.get(cl);
    +        if (registrations != null && registrations.containsValue(globalName)) {
    +            return true;
    +        }
    +        return false;
    +    }
    +
    +
         // -------------------------------------------------- ObjectFactory Methods
     
         /**
    @@ -82,6 +137,12 @@ public Object getObjectInstance(Object obj, Name name, Context nameCtx,
             RefAddr refAddr = ref.get(ResourceLinkRef.GLOBALNAME);
             if (refAddr != null) {
                 globalName = refAddr.getContent().toString();
    +            // When running under a security manager confirm that the current
    +            // web application has really been configured to access the specified
    +            // global resource
    +            if (!validateGlobalResourceAccess(globalName)) {
    +                return null;
    +            }
                 Object result = null;
                 result = globalContext.lookup(globalName);
                 // Check the expected type
    
  • test/org/apache/naming/TestNamingContext.java+87 0 added
    @@ -0,0 +1,87 @@
    +package org.apache.naming;
    +
    +import javax.naming.Context;
    +import javax.naming.NamingException;
    +
    +import org.apache.catalina.startup.Tomcat;
    +import org.apache.catalina.startup.TomcatBaseTest;
    +import org.apache.naming.factory.ResourceLinkFactory;
    +import org.apache.tomcat.util.descriptor.web.ContextEnvironment;
    +import org.apache.tomcat.util.descriptor.web.ContextResourceLink;
    +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;
    +    }
    +}
    
  • webapps/docs/changelog.xml+5 0 modified
    @@ -153,6 +153,11 @@
             >CVE-2016-5388</a>) by default and to provide a mechanism that can be
             used to mitigate any future, similar issues. (markt)
           </add>
    +      <add>
    +        When adding and removing <code>ResourceLink</code>s dynamically, ensure
    +        that the global resource is only visible via the
    +        <code>ResourceLinkFactory</code> when it is meant to be. (markt)
    +      </add>
         </changelog>
       </subsection>
       <subsection name="Coyote">
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

50

News mentions

0

No linked articles in our index yet.