This is an automated email from the git hooks/post-receive script. ebourg-guest pushed a commit to branch jessie in repository tomcat8.
commit 8515831a6046892d0ba9286fed6785edb656e77a Author: Emmanuel Bourg <[email protected]> Date: Sat Nov 12 01:47:14 2016 +0100 Fixed CVE-2016-6797: Unrestricted Access to Global Resources --- debian/changelog | 5 + debian/patches/CVE-2016-6797.patch | 244 +++++++++++++++++++++++++++++++++++++ debian/patches/series | 1 + 3 files changed, 250 insertions(+) diff --git a/debian/changelog b/debian/changelog index 90c6fef..538452b 100644 --- a/debian/changelog +++ b/debian/changelog @@ -8,6 +8,11 @@ tomcat8 (8.0.14-1+deb8u4) UNRELEASED; urgency=medium the SecurityManager. Tomcat's system property replacement feature for configuration files could be used by a malicious web application to bypass the SecurityManager and read system properties that should not be visible. + * Fixed 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. * CVE-2016-1240 follow-up: - The previous init.d fix was vulnerable to a race condition that could be exploited to make any existing file writable by the tomcat user. diff --git a/debian/patches/CVE-2016-6797.patch b/debian/patches/CVE-2016-6797.patch new file mode 100644 index 0000000..ac6a2ec --- /dev/null +++ b/debian/patches/CVE-2016-6797.patch @@ -0,0 +1,244 @@ +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/r1757273 +--- a/java/org/apache/catalina/core/NamingContextListener.java ++++ b/java/org/apache/catalina/core/NamingContextListener.java +@@ -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 @@ + registry.unregisterComponent(objectName); + } + } ++ ++ javax.naming.Context global = getGlobalNamingContext(); ++ if (global != null) { ++ ResourceLinkFactory.deregisterGlobalResourceAccess(global); ++ } + } finally { + objectNames.clear(); + +@@ -1148,6 +1155,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; + } + + +@@ -1251,6 +1269,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 +@@ -18,7 +18,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; +@@ -50,6 +53,8 @@ + */ + private static Context globalContext = null; + ++ private static Map<ClassLoader,Map<String,String>> globalResourceRegistrations = ++ new ConcurrentHashMap<>(); + + // --------------------------------------------------------- Public Methods + +@@ -69,6 +74,56 @@ + } + + ++ 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 + + +@@ -93,6 +148,12 @@ + 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); + // FIXME: Check type +--- /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.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; ++ } ++} diff --git a/debian/patches/series b/debian/patches/series index 014dab2..a6925fa 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -23,3 +23,4 @@ CVE-2016-0763.patch CVE-2016-3092.patch CVE-2016-5018.patch CVE-2016-6794.patch +CVE-2016-6797.patch -- Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-java/tomcat8.git _______________________________________________ pkg-java-commits mailing list [email protected] http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/pkg-java-commits

