[tomcat8] 06/08: Fixed CVE-2016-6797: Unrestricted Access to Global Resources
Emmanuel Bourg
ebourg-guest at moszumanska.debian.org
Sat Nov 12 01:15:33 UTC 2016
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 <ebourg at apache.org>
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
More information about the pkg-java-commits
mailing list