diff -Nru tomcat7-7.0.52/debian/changelog tomcat7-7.0.52/debian/changelog --- tomcat7-7.0.52/debian/changelog 2016-09-16 13:28:12.000000000 +0000 +++ tomcat7-7.0.52/debian/changelog 2017-01-19 17:53:04.000000000 +0000 @@ -1,3 +1,75 @@ +tomcat7 (7.0.52-1ubuntu0.8) trusty-security; urgency=medium + + * SECURITY UPDATE: SecurityManager bypass via a utility method + - debian/patches/CVE-2016-5018.patch: remove unnecessary code in + java/org/apache/jasper/compiler/JspRuntimeContext.java, + java/org/apache/jasper/runtime/JspRuntimeLibrary.java, + java/org/apache/jasper/security/SecurityClassLoad.java. + - CVE-2016-5018 + * SECURITY UPDATE: mitigaton for httpoxy issue + - debian/patches/CVE-2016-5388.patch: add envHttpHeaders initialization + parameter to conf/web.xml, webapps/docs/cgi-howto.xml, + java/org/apache/catalina/servlets/CGIServlet.java. + - CVE-2016-5388 + * SECURITY UPDATE: system properties read SecurityManager bypass + - debian/patches/CVE-2016-6794.patch: extend SecurityManager protection + to the system property replacement feature of the digester in + java/org/apache/catalina/loader/WebappClassLoader.java, + java/org/apache/tomcat/util/digester/Digester.java, + java/org/apache/tomcat/util/security/PermissionCheck.java. + - CVE-2016-6794 + * SECURITY UPDATE: SecurityManager bypass via JSP Servlet configuration + parameters + - debian/patches/CVE-2016-6796.patch: ignore some JSP options when + running under a SecurityManager in conf/web.xml, + java/org/apache/jasper/EmbeddedServletOptions.java, + java/org/apache/jasper/resources/LocalStrings.properties, + java/org/apache/jasper/servlet/JspServlet.java, + webapps/docs/jasper-howto.xml. + - CVE-2016-6796 + * SECURITY UPDATE: web application global JNDI resource access + - debian/patches/CVE-2016-6797.patch: ensure that the global resource + is only visible via the ResourceLinkFactory when it is meant to be in + java/org/apache/catalina/core/NamingContextListener.java, + java/org/apache/naming/factory/ResourceLinkFactory.java, + test/org/apache/naming/TestNamingContext.java. + - CVE-2016-6797 + * SECURITY UPDATE: HTTP response injection via invalid characters + - debian/patches/CVE-2016-6816.patch: add additional checks for valid + characters in java/org/apache/coyote/http11/AbstractInputBuffer.java, + java/org/apache/coyote/http11/AbstractNioInputBuffer.java, + java/org/apache/coyote/http11/InternalAprInputBuffer.java, + java/org/apache/coyote/http11/InternalInputBuffer.java, + java/org/apache/coyote/http11/LocalStrings.properties, + java/org/apache/tomcat/util/http/parser/HttpParser.java. + - CVE-2016-6816 + * SECURITY UPDATE: remote code execution via JmxRemoteLifecycleListener + - debian/patches/CVE-2016-8735-pre.patch: remove the restriction that + prevented the use of SSL when specifying a bind address in + java/org/apache/catalina/mbeans/JmxRemoteLifecycleListener.java, + java/org/apache/catalina/mbeans/LocalStrings.properties, + webapps/docs/config/listeners.xml. + - debian/patches/CVE-2016-8735.patch: explicitly configure allowed + credential types in + java/org/apache/catalina/mbeans/JmxRemoteLifecycleListener.java. + - CVE-2016-8735 + * SECURITY UPDATE: information leakage between requests + - debian/patches/CVE-2016-8745.patch: properly handle cache when unable + to complete sendfile request in + java/org/apache/tomcat/util/net/NioEndpoint.java. + - CVE-2016-8745 + * SECURITY UPDATE: privilege escalation during package upgrade + - debian/rules, debian/tomcat7.postinst: properly set permissions on + /etc/tomcat7/Catalina/localhost. + - CVE-2016-9774 + * SECURITY UPDATE: privilege escalation during package removal + - debian/tomcat7.postrm.in: don't reset permissions before removing + user. + - CVE-2016-9775 + * debian/tomcat7.init: further hardening. + + -- Marc Deslauriers Thu, 19 Jan 2017 12:38:29 -0500 + tomcat7 (7.0.52-1ubuntu0.7) trusty-security; urgency=medium * SECURITY UPDATE: privilege escalation via insecure init script diff -Nru tomcat7-7.0.52/debian/patches/CVE-2016-5018.patch tomcat7-7.0.52/debian/patches/CVE-2016-5018.patch --- tomcat7-7.0.52/debian/patches/CVE-2016-5018.patch 1970-01-01 00:00:00.000000000 +0000 +++ tomcat7-7.0.52/debian/patches/CVE-2016-5018.patch 2017-01-19 17:42:46.000000000 +0000 @@ -0,0 +1,130 @@ +Description: fix SecurityManager bypass via a utility method +Origin: backport, https://svn.apache.org/viewvc?view=revision&revision=1754902 +Origin: backport, https://svn.apache.org/viewvc?view=revision&revision=1760309 +Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=842663 +Bug: https://bz.apache.org/bugzilla/show_bug.cgi?id=60101 + +Index: tomcat7-7.0.52/java/org/apache/jasper/compiler/JspRuntimeContext.java +=================================================================== +--- tomcat7-7.0.52.orig/java/org/apache/jasper/compiler/JspRuntimeContext.java 2014-01-27 08:35:02.000000000 -0500 ++++ tomcat7-7.0.52/java/org/apache/jasper/compiler/JspRuntimeContext.java 2017-01-18 09:17:48.900398996 -0500 +@@ -90,8 +90,6 @@ + factory.getClass().getClassLoader().loadClass( basePackage + + "runtime.JspRuntimeLibrary"); + factory.getClass().getClassLoader().loadClass( basePackage + +- "runtime.JspRuntimeLibrary$PrivilegedIntrospectHelper"); +- factory.getClass().getClassLoader().loadClass( basePackage + + "runtime.ServletResponseWrapperInclude"); + factory.getClass().getClassLoader().loadClass( basePackage + + "servlet.JspServletWrapper"); +Index: tomcat7-7.0.52/java/org/apache/jasper/runtime/JspRuntimeLibrary.java +=================================================================== +--- tomcat7-7.0.52.orig/java/org/apache/jasper/runtime/JspRuntimeLibrary.java 2014-01-27 08:35:02.000000000 -0500 ++++ tomcat7-7.0.52/java/org/apache/jasper/runtime/JspRuntimeLibrary.java 2017-01-18 09:17:46.480362426 -0500 +@@ -14,7 +14,6 @@ + * See the License for the specific language governing permissions and + * limitations under the License. + */ +- + package org.apache.jasper.runtime; + + import java.beans.PropertyEditor; +@@ -23,9 +22,6 @@ + import java.io.IOException; + import java.io.OutputStreamWriter; + import java.lang.reflect.Method; +-import java.security.AccessController; +-import java.security.PrivilegedActionException; +-import java.security.PrivilegedExceptionAction; + import java.util.Enumeration; + + import javax.servlet.RequestDispatcher; +@@ -37,7 +33,6 @@ + import javax.servlet.jsp.PageContext; + import javax.servlet.jsp.tagext.BodyContent; + +-import org.apache.jasper.Constants; + import org.apache.jasper.JasperException; + import org.apache.jasper.compiler.Localizer; + import org.apache.jasper.util.ExceptionUtils; +@@ -56,36 +51,6 @@ + */ + public class JspRuntimeLibrary { + +- protected static class PrivilegedIntrospectHelper +- implements PrivilegedExceptionAction { +- +- private Object bean; +- private String prop; +- private String value; +- private ServletRequest request; +- private String param; +- private boolean ignoreMethodNF; +- +- PrivilegedIntrospectHelper(Object bean, String prop, +- String value, ServletRequest request, +- String param, boolean ignoreMethodNF) +- { +- this.bean = bean; +- this.prop = prop; +- this.value = value; +- this.request = request; +- this.param = param; +- this.ignoreMethodNF = ignoreMethodNF; +- } +- +- @Override +- public Void run() throws JasperException { +- internalIntrospecthelper( +- bean,prop,value,request,param,ignoreMethodNF); +- return null; +- } +- } +- + /** + * Returns the value of the javax.servlet.error.exception request + * attribute value, if present, otherwise the value of the +@@ -290,29 +255,7 @@ + public static void introspecthelper(Object bean, String prop, + String value, ServletRequest request, + String param, boolean ignoreMethodNF) +- throws JasperException +- { +- if( Constants.IS_SECURITY_ENABLED ) { +- try { +- PrivilegedIntrospectHelper dp = +- new PrivilegedIntrospectHelper( +- bean,prop,value,request,param,ignoreMethodNF); +- AccessController.doPrivileged(dp); +- } catch( PrivilegedActionException pe) { +- Exception e = pe.getException(); +- throw (JasperException)e; +- } +- } else { +- internalIntrospecthelper( +- bean,prop,value,request,param,ignoreMethodNF); +- } +- } +- +- private static void internalIntrospecthelper(Object bean, String prop, +- String value, ServletRequest request, +- String param, boolean ignoreMethodNF) +- throws JasperException +- { ++ throws JasperException { + Method method = null; + Class type = null; + Class propertyEditorClass = null; +Index: tomcat7-7.0.52/java/org/apache/jasper/security/SecurityClassLoad.java +=================================================================== +--- tomcat7-7.0.52.orig/java/org/apache/jasper/security/SecurityClassLoad.java 2017-01-18 09:17:31.000000000 -0500 ++++ tomcat7-7.0.52/java/org/apache/jasper/security/SecurityClassLoad.java 2017-01-18 09:17:48.900398996 -0500 +@@ -46,8 +46,6 @@ + + loader.loadClass( basePackage + + "runtime.JspRuntimeLibrary"); +- loader.loadClass( basePackage + +- "runtime.JspRuntimeLibrary$PrivilegedIntrospectHelper"); + + loader.loadClass( basePackage + + "runtime.ServletResponseWrapperInclude"); diff -Nru tomcat7-7.0.52/debian/patches/CVE-2016-5388.patch tomcat7-7.0.52/debian/patches/CVE-2016-5388.patch --- tomcat7-7.0.52/debian/patches/CVE-2016-5388.patch 1970-01-01 00:00:00.000000000 +0000 +++ tomcat7-7.0.52/debian/patches/CVE-2016-5388.patch 2017-01-19 17:44:21.000000000 +0000 @@ -0,0 +1,104 @@ +Description: add mitigaton for httpoxy issue +Origin: backport, https://svn.apache.org/viewvc?view=revision&revision=1756942 + +Index: tomcat7-7.0.52/conf/web.xml +=================================================================== +--- tomcat7-7.0.52.orig/conf/web.xml 2017-01-18 09:17:31.000000000 -0500 ++++ tomcat7-7.0.52/conf/web.xml 2017-01-18 09:18:03.996626843 -0500 +@@ -321,6 +321,15 @@ + + + ++ ++ ++ ++ ++ ++ ++ ++ ++ + + + +@@ -344,7 +353,7 @@ + cgiPathPrefix + WEB-INF/cgi + +- 5 ++ 5 + + --> + +Index: tomcat7-7.0.52/java/org/apache/catalina/servlets/CGIServlet.java +=================================================================== +--- tomcat7-7.0.52.orig/java/org/apache/catalina/servlets/CGIServlet.java 2014-01-27 09:53:14.000000000 -0500 ++++ tomcat7-7.0.52/java/org/apache/catalina/servlets/CGIServlet.java 2017-01-18 09:18:03.996626843 -0500 +@@ -36,6 +36,7 @@ + import java.util.Locale; + import java.util.StringTokenizer; + import java.util.Vector; ++import java.util.regex.Pattern; + + import javax.servlet.RequestDispatcher; + import javax.servlet.ServletConfig; +@@ -268,6 +269,16 @@ + */ + private long stderrTimeout = 2000; + ++ /** ++ * The regular expression used to select HTTP headers to be passed to the ++ * CGI process as environment variables. The name of the environment ++ * variable will be the name of the HTTP header converter to upper case, ++ * prefixed with HTTP_ and with all - characters ++ * converted to _. ++ */ ++ private Pattern envHttpHeadersPattern = Pattern.compile( ++ "ACCEPT[-0-9A-Z]*|CACHE-CONTROL|COOKIE|HOST|IF-[-0-9A-Z]*|REFERER|USER-AGENT"); ++ + /** object used to ensure multiple threads don't try to expand same file */ + static Object expandFileLock = new Object(); + +@@ -331,6 +342,10 @@ + "stderrTimeout")); + } + ++ if (getServletConfig().getInitParameter("envHttpHeaders") != null) { ++ envHttpHeadersPattern = ++ Pattern.compile(getServletConfig().getInitParameter("envHttpHeaders")); ++ } + } + + +@@ -1072,12 +1087,8 @@ + //REMIND: rewrite multiple headers as if received as single + //REMIND: change character set + //REMIND: I forgot what the previous REMIND means +- if ("AUTHORIZATION".equalsIgnoreCase(header) || +- "PROXY_AUTHORIZATION".equalsIgnoreCase(header)) { +- //NOOP per CGI specification section 11.2 +- } else { +- envp.put("HTTP_" + header.replace('-', '_'), +- req.getHeader(header)); ++ if (envHttpHeadersPattern.matcher(header).matches()) { ++ envp.put("HTTP_" + header.replace('-', '_'), req.getHeader(header)); + } + } + +Index: tomcat7-7.0.52/webapps/docs/cgi-howto.xml +=================================================================== +--- tomcat7-7.0.52.orig/webapps/docs/cgi-howto.xml 2014-01-26 17:13:11.000000000 -0500 ++++ tomcat7-7.0.52/webapps/docs/cgi-howto.xml 2017-01-18 09:18:03.996626843 -0500 +@@ -86,6 +86,12 @@ +
  • executable-arg-1, executable-arg-2, + and so on - additional arguments for the executable. These precede the + CGI script name. By default there are no additional arguments.
  • ++
  • envHttpHeaders - A regular expression used to select the ++HTTP headers passed to the CGI process as environment variables. Note that ++headers are converted to upper case before matching and that the entire header ++name must match the pattern. Default is ++ACCEPT[-0-9A-Z]*|CACHE-CONTROL|COOKIE|HOST|IF-[-0-9A-Z]*|REFERER|USER-AGENT ++
  • +
  • parameterEncoding - Name of the parameter encoding + to be used with the CGI servlet. Default is + System.getProperty("file.encoding","UTF-8").
  • diff -Nru tomcat7-7.0.52/debian/patches/CVE-2016-6794.patch tomcat7-7.0.52/debian/patches/CVE-2016-6794.patch --- tomcat7-7.0.52/debian/patches/CVE-2016-6794.patch 1970-01-01 00:00:00.000000000 +0000 +++ tomcat7-7.0.52/debian/patches/CVE-2016-6794.patch 2017-01-19 17:44:46.000000000 +0000 @@ -0,0 +1,141 @@ +Description: fix system properties read SecurityManager bypass +Origin: backport, https://svn.apache.org/viewvc?view=revision&revision=1754728 +Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=842664 + +Index: tomcat7-7.0.52/java/org/apache/catalina/loader/WebappClassLoader.java +=================================================================== +--- tomcat7-7.0.52.orig/java/org/apache/catalina/loader/WebappClassLoader.java 2014-01-27 09:53:14.000000000 -0500 ++++ tomcat7-7.0.52/java/org/apache/catalina/loader/WebappClassLoader.java 2017-01-18 09:21:16.875497156 -0500 +@@ -79,6 +79,7 @@ + import org.apache.tomcat.util.ExceptionUtils; + import org.apache.tomcat.util.IntrospectionUtils; + import org.apache.tomcat.util.res.StringManager; ++import org.apache.tomcat.util.security.PermissionCheck; + + /** + * Specialized web application class loader. +@@ -123,7 +124,7 @@ + */ + public class WebappClassLoader + extends URLClassLoader +- implements Lifecycle ++ implements Lifecycle, PermissionCheck + { + + private static final org.apache.juli.logging.Log log= +@@ -1751,6 +1752,27 @@ + } + + ++ @Override ++ public boolean check(Permission permission) { ++ if (!Globals.IS_SECURITY_ENABLED) { ++ return true; ++ } ++ Policy currentPolicy = Policy.getPolicy(); ++ if (currentPolicy != null) { ++ ResourceEntry entry = findResourceInternal("/", "/"); ++ if (entry != null) { ++ CodeSource cs = new CodeSource( ++ entry.codeBase, (java.security.cert.Certificate[]) null); ++ PermissionCollection pc = currentPolicy.getPermissions(cs); ++ if (pc.implies(permission)) { ++ return true; ++ } ++ } ++ } ++ return false; ++ } ++ ++ + /** + * Returns the search path of URLs for loading classes and resources. + * This includes the original list of URLs specified to the constructor, +Index: tomcat7-7.0.52/java/org/apache/tomcat/util/digester/Digester.java +=================================================================== +--- tomcat7-7.0.52.orig/java/org/apache/tomcat/util/digester/Digester.java 2014-01-27 07:42:39.000000000 -0500 ++++ tomcat7-7.0.52/java/org/apache/tomcat/util/digester/Digester.java 2017-01-18 09:19:17.473729084 -0500 +@@ -26,11 +26,13 @@ + import java.lang.reflect.InvocationTargetException; + import java.net.URI; + import java.net.URISyntaxException; ++import java.security.Permission; + import java.util.EmptyStackException; + import java.util.HashMap; + import java.util.Iterator; + import java.util.List; + import java.util.Map; ++import java.util.PropertyPermission; + + import javax.xml.parsers.ParserConfigurationException; + import javax.xml.parsers.SAXParser; +@@ -40,6 +42,7 @@ + import org.apache.juli.logging.LogFactory; + import org.apache.tomcat.util.ExceptionUtils; + import org.apache.tomcat.util.IntrospectionUtils; ++import org.apache.tomcat.util.security.PermissionCheck; + import org.xml.sax.Attributes; + import org.xml.sax.EntityResolver; + import org.xml.sax.ErrorHandler; +@@ -81,6 +84,13 @@ + implements IntrospectionUtils.PropertySource { + @Override + public String getProperty( String key ) { ++ ClassLoader cl = Thread.currentThread().getContextClassLoader(); ++ if (cl instanceof PermissionCheck) { ++ Permission p = new PropertyPermission(key, "read"); ++ if (!((PermissionCheck) cl).check(p)) { ++ return null; ++ } ++ } + return System.getProperty(key); + } + } +Index: tomcat7-7.0.52/java/org/apache/tomcat/util/security/PermissionCheck.java +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ tomcat7-7.0.52/java/org/apache/tomcat/util/security/PermissionCheck.java 2017-01-18 09:19:17.477729143 -0500 +@@ -0,0 +1,43 @@ ++/* ++ * Licensed to the Apache Software Foundation (ASF) under one or more ++ * contributor license agreements. See the NOTICE file distributed with ++ * this work for additional information regarding copyright ownership. ++ * 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.tomcat.util.security; ++ ++import java.security.Permission; ++ ++/** ++ * This interface is implemented by components to enable privileged code to ++ * check whether the component has a given permission. ++ * This is typically used when a privileged component (e.g. the container) is ++ * performing an action on behalf of an untrusted component (e.g. a web ++ * application) without the current thread having passed through a code source ++ * provided by the untrusted component. Because the current thread has not ++ * passed through a code source provided by the untrusted component the ++ * SecurityManager assumes the code is trusted so the standard checking ++ * mechanisms can't be used. ++ */ ++public interface PermissionCheck { ++ ++ /** ++ * Does this component have the given permission? ++ * ++ * @param permission The permission to test ++ * ++ * @return {@code false} if a SecurityManager is enabled and the component ++ * does not have the given permission, otherwise {@code false} ++ */ ++ boolean check(Permission permission); ++} diff -Nru tomcat7-7.0.52/debian/patches/CVE-2016-6796.patch tomcat7-7.0.52/debian/patches/CVE-2016-6796.patch --- tomcat7-7.0.52/debian/patches/CVE-2016-6796.patch 1970-01-01 00:00:00.000000000 +0000 +++ tomcat7-7.0.52/debian/patches/CVE-2016-6796.patch 2017-01-19 17:45:34.000000000 +0000 @@ -0,0 +1,101 @@ +Description: fix SecurityManager bypass via JSP Servlet configuration parameters +Origin: backport, https://svn.apache.org/viewvc?view=rev&rev=1758495 + +Index: tomcat7-7.0.52/conf/web.xml +=================================================================== +--- tomcat7-7.0.52.orig/conf/web.xml 2017-01-18 09:18:03.996626843 -0500 ++++ tomcat7-7.0.52/conf/web.xml 2017-01-18 09:21:44.851907437 -0500 +@@ -158,6 +158,8 @@ + + + ++ ++ + + + +@@ -219,6 +221,8 @@ + + + ++ ++ + + + +Index: tomcat7-7.0.52/java/org/apache/jasper/EmbeddedServletOptions.java +=================================================================== +--- tomcat7-7.0.52.orig/java/org/apache/jasper/EmbeddedServletOptions.java 2014-01-27 08:35:02.000000000 -0500 ++++ tomcat7-7.0.52/java/org/apache/jasper/EmbeddedServletOptions.java 2017-01-18 09:21:44.847907378 -0500 +@@ -635,6 +635,10 @@ + * scratchdir + */ + String dir = config.getInitParameter("scratchdir"); ++ if (dir != null && Constants.IS_SECURITY_ENABLED) { ++ log.info(Localizer.getMessage("jsp.info.ignoreSetting", "scratchdir", dir)); ++ dir = null; ++ } + if (dir != null) { + scratchDir = new File(dir); + } else { +Index: tomcat7-7.0.52/java/org/apache/jasper/resources/LocalStrings.properties +=================================================================== +--- tomcat7-7.0.52.orig/java/org/apache/jasper/resources/LocalStrings.properties 2014-01-27 08:35:02.000000000 -0500 ++++ tomcat7-7.0.52/java/org/apache/jasper/resources/LocalStrings.properties 2017-01-18 09:21:44.851907437 -0500 +@@ -454,6 +454,7 @@ + jsp.error.invalid.bean=The value for the useBean class attribute {0} is invalid. + jsp.error.prefix.use_before_dcl=The prefix {0} specified in this tag directive has been previously used by an action in file {1} line {2}. + jsp.error.lastModified=Unable to determine last modified date for file [{0}] ++jsp.info.ignoreSetting=Ignored setting for [{0}] of [{1}] because a SecurityManager was enabled + + jsp.exception=An exception occurred processing JSP page {0} at line {1} + +Index: tomcat7-7.0.52/java/org/apache/jasper/servlet/JspServlet.java +=================================================================== +--- tomcat7-7.0.52.orig/java/org/apache/jasper/servlet/JspServlet.java 2014-01-27 08:35:02.000000000 -0500 ++++ tomcat7-7.0.52/java/org/apache/jasper/servlet/JspServlet.java 2017-01-18 09:22:20.916434163 -0500 +@@ -71,8 +71,8 @@ + private ServletConfig config; + private transient Options options; + private transient JspRuntimeContext rctxt; +- //jspFile for a jsp configured explicitly as a servlet, in environments where this configuration is +- //translated into an init-param for this servlet. ++ // jspFile for a jsp configured explicitly as a servlet, in environments where this ++ // configuration is translated into an init-param for this servlet. + private String jspFile; + + +@@ -90,6 +90,11 @@ + // Check for a custom Options implementation + String engineOptionsName = + config.getInitParameter("engineOptionsClass"); ++ if (Constants.IS_SECURITY_ENABLED && engineOptionsName != null) { ++ log.info(Localizer.getMessage( ++ "jsp.info.ignoreSetting", "engineOptionsClass", engineOptionsName)); ++ engineOptionsName = null; ++ } + if (engineOptionsName != null) { + // Instantiate the indicated Options implementation + try { +Index: tomcat7-7.0.52/webapps/docs/jasper-howto.xml +=================================================================== +--- tomcat7-7.0.52.orig/webapps/docs/jasper-howto.xml 2014-01-26 17:13:11.000000000 -0500 ++++ tomcat7-7.0.52/webapps/docs/jasper-howto.xml 2017-01-18 09:21:44.851907437 -0500 +@@ -132,7 +132,7 @@ + +
  • engineOptionsClass - Allows specifying the Options class + used to configure Jasper. If not present, the default EmbeddedServletOptions +-will be used. ++will be used. This option is ignored if running under a SecurityManager. +
  • + +
  • errorOnUseBeanInvalidClassAttribute - Should Jasper issue +@@ -185,7 +185,7 @@ + +
  • scratchdir - What scratch directory should we use when + compiling JSP pages? Default is the work directory for the current web +-application.
  • ++application. This option is ignored if running under a SecurityManager. + +
  • suppressSmap - Should the generation of SMAP info for JSR45 + debugging be suppressed? true or false, default diff -Nru tomcat7-7.0.52/debian/patches/CVE-2016-6797.patch tomcat7-7.0.52/debian/patches/CVE-2016-6797.patch --- tomcat7-7.0.52/debian/patches/CVE-2016-6797.patch 1970-01-01 00:00:00.000000000 +0000 +++ tomcat7-7.0.52/debian/patches/CVE-2016-6797.patch 2017-01-19 17:46:54.000000000 +0000 @@ -0,0 +1,262 @@ +Description: fix web application global JNDI resource access +Origin: backport, https://svn.apache.org/viewvc?view=revision&revision=1757275 +Origin: backport, https://svn.apache.org/viewvc?view=revision&revision=1763236 +Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=842666 +Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=845425 + +Index: tomcat7-7.0.52/java/org/apache/catalina/core/NamingContextListener.java +=================================================================== +--- tomcat7-7.0.52.orig/java/org/apache/catalina/core/NamingContextListener.java 2014-01-27 09:53:14.000000000 -0500 ++++ tomcat7-7.0.52/java/org/apache/catalina/core/NamingContextListener.java 2017-01-18 09:25:22.003043483 -0500 +@@ -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; + +@@ -334,6 +336,11 @@ + for (ObjectName objectName : names) { + Registry.getRegistry(null, null).unregisterComponent(objectName); + } ++ javax.naming.Context global = getGlobalNamingContext(); ++ if (global != null) { ++ ResourceLinkFactory.deregisterGlobalResourceAccess(global); ++ } ++ + objectNames.clear(); + + namingContext = null; +@@ -1155,6 +1162,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; + } + + +@@ -1258,6 +1276,7 @@ + logger.error(sm.getString("naming.unbindFailed", e)); + } + ++ ResourceLinkFactory.deregisterGlobalResourceAccess(getGlobalNamingContext(), name); + } + + +Index: tomcat7-7.0.52/java/org/apache/naming/factory/ResourceLinkFactory.java +=================================================================== +--- tomcat7-7.0.52.orig/java/org/apache/naming/factory/ResourceLinkFactory.java 2017-01-18 09:17:31.000000000 -0500 ++++ tomcat7-7.0.52/java/org/apache/naming/factory/ResourceLinkFactory.java 2017-01-18 09:27:10.896585540 -0500 +@@ -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; +@@ -32,7 +35,7 @@ + + /** + *

    Object factory for resource links.

    +- * ++ * + * @author Remy Maucherat + */ + public class ResourceLinkFactory +@@ -50,6 +53,8 @@ + */ + private static Context globalContext = null; + ++ private static Map> globalResourceRegistrations = ++ new ConcurrentHashMap>(); + + // --------------------------------------------------------- Public Methods + +@@ -69,6 +74,59 @@ + } + + ++ public static void registerGlobalResourceAccess(Context globalContext, String localName, ++ String globalName) { ++ validateGlobalContext(globalContext); ++ ClassLoader cl = Thread.currentThread().getContextClassLoader(); ++ Map 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 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 registrations = globalResourceRegistrations.get(cl); ++ if (registrations != null && registrations.containsValue(globalName)) { ++ return true; ++ } ++ cl = cl.getParent(); ++ } ++ return false; ++ } ++ ++ + // -------------------------------------------------- ObjectFactory Methods + + +@@ -93,6 +151,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 +Index: tomcat7-7.0.52/test/org/apache/naming/TestNamingContext.java +=================================================================== +--- /dev/null 1970-01-01 00:00:00.000000000 +0000 ++++ tomcat7-7.0.52/test/org/apache/naming/TestNamingContext.java 2017-01-18 09:22:50.172859691 -0500 +@@ -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("", System.getProperty("java.io.tmpdir")); ++ ++ 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 -Nru tomcat7-7.0.52/debian/patches/CVE-2016-6816.patch tomcat7-7.0.52/debian/patches/CVE-2016-6816.patch --- tomcat7-7.0.52/debian/patches/CVE-2016-6816.patch 1970-01-01 00:00:00.000000000 +0000 +++ tomcat7-7.0.52/debian/patches/CVE-2016-6816.patch 2017-01-19 17:47:40.000000000 +0000 @@ -0,0 +1,447 @@ +Description: fix HTTP response injection via invalid characters +Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=802312 +Origin: backport, http://svn.apache.org/r1767675 + +Index: tomcat7-7.0.52/java/org/apache/coyote/http11/AbstractInputBuffer.java +=================================================================== +--- tomcat7-7.0.52.orig/java/org/apache/coyote/http11/AbstractInputBuffer.java 2017-01-18 13:37:43.367056800 -0500 ++++ tomcat7-7.0.52/java/org/apache/coyote/http11/AbstractInputBuffer.java 2017-01-18 13:37:43.363056748 -0500 +@@ -28,64 +28,10 @@ + + public abstract class AbstractInputBuffer implements InputBuffer{ + +- protected static final boolean[] HTTP_TOKEN_CHAR = new boolean[128]; +- + /** + * The string manager for this package. + */ +- protected static final StringManager sm = +- StringManager.getManager(Constants.Package); +- +- +- static { +- for (int i = 0; i < 128; i++) { +- if (i < 32) { +- HTTP_TOKEN_CHAR[i] = false; +- } else if (i == 127) { +- HTTP_TOKEN_CHAR[i] = false; +- } else if (i == '(') { +- HTTP_TOKEN_CHAR[i] = false; +- } else if (i == ')') { +- HTTP_TOKEN_CHAR[i] = false; +- } else if (i == '<') { +- HTTP_TOKEN_CHAR[i] = false; +- } else if (i == '>') { +- HTTP_TOKEN_CHAR[i] = false; +- } else if (i == '@') { +- HTTP_TOKEN_CHAR[i] = false; +- } else if (i == ',') { +- HTTP_TOKEN_CHAR[i] = false; +- } else if (i == ';') { +- HTTP_TOKEN_CHAR[i] = false; +- } else if (i == ':') { +- HTTP_TOKEN_CHAR[i] = false; +- } else if (i == '\\') { +- HTTP_TOKEN_CHAR[i] = false; +- } else if (i == '\"') { +- HTTP_TOKEN_CHAR[i] = false; +- } else if (i == '/') { +- HTTP_TOKEN_CHAR[i] = false; +- } else if (i == '[') { +- HTTP_TOKEN_CHAR[i] = false; +- } else if (i == ']') { +- HTTP_TOKEN_CHAR[i] = false; +- } else if (i == '?') { +- HTTP_TOKEN_CHAR[i] = false; +- } else if (i == '=') { +- HTTP_TOKEN_CHAR[i] = false; +- } else if (i == '{') { +- HTTP_TOKEN_CHAR[i] = false; +- } else if (i == '}') { +- HTTP_TOKEN_CHAR[i] = false; +- } else if (i == ' ') { +- HTTP_TOKEN_CHAR[i] = false; +- } else if (i == '\t') { +- HTTP_TOKEN_CHAR[i] = false; +- } else { +- HTTP_TOKEN_CHAR[i] = true; +- } +- } +- } ++ protected static final StringManager sm = StringManager.getManager(Constants.Package); + + + /** +Index: tomcat7-7.0.52/java/org/apache/coyote/http11/InternalAprInputBuffer.java +=================================================================== +--- tomcat7-7.0.52.orig/java/org/apache/coyote/http11/InternalAprInputBuffer.java 2017-01-18 13:37:43.367056800 -0500 ++++ tomcat7-7.0.52/java/org/apache/coyote/http11/InternalAprInputBuffer.java 2017-01-18 13:37:43.363056748 -0500 +@@ -30,6 +30,7 @@ + import org.apache.tomcat.jni.Status; + import org.apache.tomcat.util.buf.ByteChunk; + import org.apache.tomcat.util.buf.MessageBytes; ++import org.apache.tomcat.util.http.parser.HttpParser; + import org.apache.tomcat.util.net.AbstractEndpoint; + import org.apache.tomcat.util.net.SocketWrapper; + +@@ -176,6 +177,8 @@ + if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) { + space = true; + request.method().setBytes(buf, start, pos - start); ++ } else if (!HttpParser.isToken(buf[pos])) { ++ throw new IllegalArgumentException(sm.getString("iib.invalidmethod")); + } + + pos++; +@@ -219,15 +222,16 @@ + if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) { + space = true; + end = pos; +- } else if ((buf[pos] == Constants.CR) ++ } else if ((buf[pos] == Constants.CR) + || (buf[pos] == Constants.LF)) { + // HTTP/0.9 style request + eol = true; + space = true; + end = pos; +- } else if ((buf[pos] == Constants.QUESTION) +- && (questionPos == -1)) { ++ } else if ((buf[pos] == Constants.QUESTION) && (questionPos == -1)) { + questionPos = pos; ++ } else if (HttpParser.isNotRequestTarget(buf[pos])) { ++ throw new IllegalArgumentException(sm.getString("iib.invalidRequestTarget")); + } + + pos++; +@@ -264,7 +268,7 @@ + + // + // Reading the protocol +- // Protocol is always US-ASCII ++ // Protocol is always "HTTP/" DIGIT "." DIGIT + // + + while (!eol) { +@@ -281,6 +285,8 @@ + if (end == 0) + end = pos; + eol = true; ++ } else if (!HttpParser.isHttpProtocol(buf[pos])) { ++ throw new IllegalArgumentException(sm.getString("iib.invalidHttpProtocol")); + } + + pos++; +@@ -379,7 +385,7 @@ + if (buf[pos] == Constants.COLON) { + colon = true; + headerValue = headers.addValue(buf, start, pos - start); +- } else if (!HTTP_TOKEN_CHAR[buf[pos]]) { ++ } else if (!HttpParser.isToken(buf[pos])) { + // If a non-token header is detected, skip the line and + // ignore the header + skipLine(start); +Index: tomcat7-7.0.52/java/org/apache/coyote/http11/InternalInputBuffer.java +=================================================================== +--- tomcat7-7.0.52.orig/java/org/apache/coyote/http11/InternalInputBuffer.java 2017-01-18 13:37:43.367056800 -0500 ++++ tomcat7-7.0.52/java/org/apache/coyote/http11/InternalInputBuffer.java 2017-01-18 13:37:43.363056748 -0500 +@@ -28,6 +28,7 @@ + import org.apache.juli.logging.LogFactory; + import org.apache.tomcat.util.buf.ByteChunk; + import org.apache.tomcat.util.buf.MessageBytes; ++import org.apache.tomcat.util.http.parser.HttpParser; + import org.apache.tomcat.util.net.AbstractEndpoint; + import org.apache.tomcat.util.net.SocketWrapper; + +@@ -132,6 +133,8 @@ + if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) { + space = true; + request.method().setBytes(buf, start, pos - start); ++ } else if (!HttpParser.isToken(buf[pos])) { ++ throw new IllegalArgumentException(sm.getString("iib.invalidmethod")); + } + + pos++; +@@ -176,15 +179,16 @@ + if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) { + space = true; + end = pos; +- } else if ((buf[pos] == Constants.CR) ++ } else if ((buf[pos] == Constants.CR) + || (buf[pos] == Constants.LF)) { + // HTTP/0.9 style request + eol = true; + space = true; + end = pos; +- } else if ((buf[pos] == Constants.QUESTION) +- && (questionPos == -1)) { ++ } else if ((buf[pos] == Constants.QUESTION) && (questionPos == -1)) { + questionPos = pos; ++ } else if (HttpParser.isNotRequestTarget(buf[pos])) { ++ throw new IllegalArgumentException(sm.getString("iib.invalidRequestTarget")); + } + + pos++; +@@ -220,9 +224,8 @@ + + // + // Reading the protocol +- // Protocol is always US-ASCII ++ // Protocol is always "HTTP/" DIGIT "." DIGIT + // +- + while (!eol) { + + // Read new bytes if needed +@@ -237,6 +240,8 @@ + if (end == 0) + end = pos; + eol = true; ++ } else if (!HttpParser.isHttpProtocol(buf[pos])) { ++ throw new IllegalArgumentException(sm.getString("iib.invalidHttpProtocol")); + } + + pos++; +@@ -335,7 +340,7 @@ + if (buf[pos] == Constants.COLON) { + colon = true; + headerValue = headers.addValue(buf, start, pos - start); +- } else if (!HTTP_TOKEN_CHAR[buf[pos]]) { ++ } else if (!HttpParser.isToken(buf[pos])) { + // If a non-token header is detected, skip the line and + // ignore the header + skipLine(start); +Index: tomcat7-7.0.52/java/org/apache/coyote/http11/InternalNioInputBuffer.java +=================================================================== +--- tomcat7-7.0.52.orig/java/org/apache/coyote/http11/InternalNioInputBuffer.java 2017-01-18 13:37:43.367056800 -0500 ++++ tomcat7-7.0.52/java/org/apache/coyote/http11/InternalNioInputBuffer.java 2017-01-18 13:37:43.367056800 -0500 +@@ -25,6 +25,7 @@ + import org.apache.coyote.Request; + import org.apache.tomcat.util.buf.ByteChunk; + import org.apache.tomcat.util.buf.MessageBytes; ++import org.apache.tomcat.util.http.parser.HttpParser; + import org.apache.tomcat.util.net.AbstractEndpoint; + import org.apache.tomcat.util.net.NioChannel; + import org.apache.tomcat.util.net.NioEndpoint; +@@ -260,6 +261,8 @@ + if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) { + space = true; + request.method().setBytes(buf, parsingRequestLineStart, pos - parsingRequestLineStart); ++ } else if (!HttpParser.isToken(buf[pos])) { ++ throw new IllegalArgumentException(sm.getString("iib.invalidmethod")); + } + pos++; + } +@@ -300,21 +303,22 @@ + if (buf[pos] == Constants.SP || buf[pos] == Constants.HT) { + space = true; + end = pos; +- } else if ((buf[pos] == Constants.CR) ++ } else if ((buf[pos] == Constants.CR) + || (buf[pos] == Constants.LF)) { + // HTTP/0.9 style request + parsingRequestLineEol = true; + space = true; + end = pos; +- } else if ((buf[pos] == Constants.QUESTION) +- && (parsingRequestLineQPos == -1)) { ++ } else if ((buf[pos] == Constants.QUESTION) && (parsingRequestLineQPos == -1)) { + parsingRequestLineQPos = pos; ++ } else if (HttpParser.isNotRequestTarget(buf[pos])) { ++ throw new IllegalArgumentException(sm.getString("iib.invalidRequestTarget")); + } + pos++; + } + request.unparsedURI().setBytes(buf, parsingRequestLineStart, end - parsingRequestLineStart); + if (parsingRequestLineQPos >= 0) { +- request.queryString().setBytes(buf, parsingRequestLineQPos + 1, ++ request.queryString().setBytes(buf, parsingRequestLineQPos + 1, + end - parsingRequestLineQPos - 1); + request.requestURI().setBytes(buf, parsingRequestLineStart, parsingRequestLineQPos - parsingRequestLineStart); + } else { +@@ -343,10 +347,10 @@ + // Mark the current buffer position + end = 0; + } +- if (parsingRequestLinePhase == 6) { ++ if (parsingRequestLinePhase == 6) { + // + // Reading the protocol +- // Protocol is always US-ASCII ++ // Protocol is always "HTTP/" DIGIT "." DIGIT + // + while (!parsingRequestLineEol) { + // Read new bytes if needed +@@ -361,10 +365,12 @@ + if (end == 0) + end = pos; + parsingRequestLineEol = true; ++ } else if (!HttpParser.isHttpProtocol(buf[pos])) { ++ throw new IllegalArgumentException(sm.getString("iib.invalidHttpProtocol")); + } + pos++; + } +- ++ + if ( (end - parsingRequestLineStart) > 0) { + request.protocol().setBytes(buf, parsingRequestLineStart, end - parsingRequestLineStart); + } else { +@@ -553,7 +559,7 @@ + headerData.realPos = pos; + headerData.lastSignificantChar = pos; + break; +- } else if (!HTTP_TOKEN_CHAR[chr]) { ++ } else if (!HttpParser.isToken(chr)) { + // If a non-token header is detected, skip the line and + // ignore the header + headerData.lastSignificantChar = pos; +Index: tomcat7-7.0.52/java/org/apache/coyote/http11/LocalStrings.properties +=================================================================== +--- tomcat7-7.0.52.orig/java/org/apache/coyote/http11/LocalStrings.properties 2017-01-18 13:37:43.367056800 -0500 ++++ tomcat7-7.0.52/java/org/apache/coyote/http11/LocalStrings.properties 2017-01-18 13:37:43.367056800 -0500 +@@ -39,8 +39,10 @@ + http11processor.sendfile.error=Error sending data using sendfile. May be caused by invalid request attributes for start/end points + + iib.eof.error=Unexpected EOF read on the socket +-iib.invalidheader=The HTTP header line [{0}] does not conform to RFC 2616 and has been ignored. ++iib.invalidheader=The HTTP header line [{0}] does not conform to RFC 7230 and has been ignored. + iib.invalidmethod=Invalid character (CR or LF) found in method name ++iib.invalidRequestTarget=Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986 ++iib.invalidHttpProtocol=Invalid character found in the HTTP protocol + iib.parseheaders.ise.error=Unexpected state: headers already parsed. Buffer not recycled? + iib.requestheadertoolarge.error=Request header is too large + +Index: tomcat7-7.0.52/java/org/apache/tomcat/util/http/parser/HttpParser.java +=================================================================== +--- tomcat7-7.0.52.orig/java/org/apache/tomcat/util/http/parser/HttpParser.java 2017-01-18 13:37:43.367056800 -0500 ++++ tomcat7-7.0.52/java/org/apache/tomcat/util/http/parser/HttpParser.java 2017-01-18 13:38:39.275756428 -0500 +@@ -53,9 +53,14 @@ + private static final Map fieldTypes = + new HashMap(); + +- // Arrays used by isToken(), isHex() +- private static final boolean isToken[] = new boolean[128]; +- private static final boolean isHex[] = new boolean[128]; ++ private static final int ARRAY_SIZE = 128; ++ ++ private static final boolean[] IS_CONTROL = new boolean[ARRAY_SIZE]; ++ private static final boolean[] IS_SEPARATOR = new boolean[ARRAY_SIZE]; ++ private static final boolean[] IS_TOKEN = new boolean[ARRAY_SIZE]; ++ private static final boolean[] IS_HEX = new boolean[ARRAY_SIZE]; ++ private static final boolean[] IS_NOT_REQUEST_TARGET = new boolean[ARRAY_SIZE]; ++ private static final boolean[] IS_HTTP_PROTOCOL = new boolean[ARRAY_SIZE]; + + static { + // Digest field types. +@@ -77,24 +82,43 @@ + // RFC2617 says nc is 8LHEX. <">8LHEX<"> will also be accepted + fieldTypes.put("nc", FIELD_TYPE_LHEX); + +- // Setup the flag arrays +- for (int i = 0; i < 128; i++) { +- if (i < 32) { +- isToken[i] = false; +- } else if (i == '(' || i == ')' || i == '<' || i == '>' || i == '@' || +- i == ',' || i == ';' || i == ':' || i == '\\' || i == '\"' || +- i == '/' || i == '[' || i == ']' || i == '?' || i == '=' || +- i == '{' || i == '}' || i == ' ' || i == '\t') { +- isToken[i] = false; +- } else { +- isToken[i] = true; ++ for (int i = 0; i < ARRAY_SIZE; i++) { ++ // Control> 0-31, 127 ++ if (i < 32 || i == 127) { ++ IS_CONTROL[i] = true; + } + +- if (i >= '0' && i <= '9' || i >= 'A' && i <= 'F' || +- i >= 'a' && i <= 'f') { +- isHex[i] = true; +- } else { +- isHex[i] = false; ++ // Separator ++ if ( i == '(' || i == ')' || i == '<' || i == '>' || i == '@' || ++ i == ',' || i == ';' || i == ':' || i == '\\' || i == '\"' || ++ i == '/' || i == '[' || i == ']' || i == '?' || i == '=' || ++ i == '{' || i == '}' || i == ' ' || i == '\t') { ++ IS_SEPARATOR[i] = true; ++ } ++ ++ // Token: Anything 0-127 that is not a control and not a separator ++ if (!IS_CONTROL[i] && !IS_SEPARATOR[i] && i < 128) { ++ IS_TOKEN[i] = true; ++ } ++ ++ // Hex: 0-9, a-f, A-F ++ if ((i >= '0' && i <='9') || (i >= 'a' && i <= 'f') || (i >= 'A' && i <= 'F')) { ++ IS_HEX[i] = true; ++ } ++ ++ // Not valid for request target. ++ // Combination of multiple rules from RFC7230 and RFC 3986. Must be ++ // ASCII, no controls plus a few additional characters excluded ++ if (IS_CONTROL[i] || i > 127 || ++ i == ' ' || i == '\"' || i == '#' || i == '<' || i == '>' || i == '\\' || ++ i == '^' || i == '`' || i == '{' || i == '|' || i == '}') { ++ IS_NOT_REQUEST_TARGET[i] = true; ++ } ++ ++ // Not valid for HTTP protocol ++ // "HTTP/" DIGIT "." DIGIT ++ if (i == 'H' || i == 'T' || i == 'P' || i == '/' || i == '.' || (i >= '0' && i <= '9')) { ++ IS_HTTP_PROTOCOL[i] = true; + } + } + } +@@ -246,24 +270,47 @@ + return result.toString(); + } + +- private static boolean isToken(int c) { ++ public static boolean isToken(int c) { + // Fast for correct values, slower for incorrect ones + try { +- return isToken[c]; ++ return IS_TOKEN[c]; + } catch (ArrayIndexOutOfBoundsException ex) { + return false; + } + } + +- private static boolean isHex(int c) { +- // Fast for correct values, slower for incorrect ones ++ public static boolean isHex(int c) { ++ // Fast for correct values, slower for some incorrect ones ++ try { ++ return IS_HEX[c]; ++ } catch (ArrayIndexOutOfBoundsException ex) { ++ return false; ++ } ++ } ++ ++ ++ public static boolean isNotRequestTarget(int c) { ++ // Fast for valid request target characters, slower for some incorrect ++ // ones + try { +- return isHex[c]; ++ return IS_NOT_REQUEST_TARGET[c]; ++ } catch (ArrayIndexOutOfBoundsException ex) { ++ return true; ++ } ++ } ++ ++ ++ public static boolean isHttpProtocol(int c) { ++ // Fast for valid HTTP protocol characters, slower for some incorrect ++ // ones ++ try { ++ return IS_HTTP_PROTOCOL[c]; + } catch (ArrayIndexOutOfBoundsException ex) { + return false; + } + } + ++ + // Skip any LWS and return the next char + private static int skipLws(StringReader input, boolean withReset) + throws IOException { diff -Nru tomcat7-7.0.52/debian/patches/CVE-2016-8735.patch tomcat7-7.0.52/debian/patches/CVE-2016-8735.patch --- tomcat7-7.0.52/debian/patches/CVE-2016-8735.patch 1970-01-01 00:00:00.000000000 +0000 +++ tomcat7-7.0.52/debian/patches/CVE-2016-8735.patch 2017-01-19 17:51:02.000000000 +0000 @@ -0,0 +1,28 @@ +Description: fix remote code execution via JmxRemoteLifecycleListener +Origin: backport, http://svn.apache.org/viewvc?view=revision&revision=1767676 +Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=802312 + +Index: tomcat7-7.0.52/java/org/apache/catalina/mbeans/JmxRemoteLifecycleListener.java +=================================================================== +--- tomcat7-7.0.52.orig/java/org/apache/catalina/mbeans/JmxRemoteLifecycleListener.java 2017-01-18 09:40:32.291409357 -0500 ++++ tomcat7-7.0.52/java/org/apache/catalina/mbeans/JmxRemoteLifecycleListener.java 2017-01-18 09:40:50.175641847 -0500 +@@ -264,6 +264,10 @@ + serverCsf = new RmiClientLocalhostSocketFactory(serverCsf); + } + ++ env.put("jmx.remote.rmi.server.credential.types", new String[] { ++ String[].class.getName(), ++ String.class.getName() }); ++ + // Populate the env properties used to create the server + if (serverCsf != null) { + env.put(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE, serverCsf); +@@ -328,7 +332,7 @@ + cs = new RMIConnectorServer(serviceUrl, theEnv, server, + ManagementFactory.getPlatformMBeanServer()); + cs.start(); +- registry.bind("jmxrmi", server); ++ registry.bind("jmxrmi", server.toStub()); + log.info(sm.getString("jmxRemoteLifecycleListener.start", + Integer.toString(theRmiRegistryPort), + Integer.toString(theRmiServerPort), serverName)); diff -Nru tomcat7-7.0.52/debian/patches/CVE-2016-8735-pre.patch tomcat7-7.0.52/debian/patches/CVE-2016-8735-pre.patch --- tomcat7-7.0.52/debian/patches/CVE-2016-8735-pre.patch 1970-01-01 00:00:00.000000000 +0000 +++ tomcat7-7.0.52/debian/patches/CVE-2016-8735-pre.patch 2017-01-19 17:50:59.000000000 +0000 @@ -0,0 +1,396 @@ +Description: remove the restriction that prevented the use of SSL when + specifying a bind address. +Origin: backport, http://svn.apache.org/viewvc?view=revision&revision=1666762 +Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=802312 + +Index: tomcat7-7.0.52/java/org/apache/catalina/mbeans/JmxRemoteLifecycleListener.java +=================================================================== +--- tomcat7-7.0.52.orig/java/org/apache/catalina/mbeans/JmxRemoteLifecycleListener.java 2017-01-18 09:38:24.000000000 -0500 ++++ tomcat7-7.0.52/java/org/apache/catalina/mbeans/JmxRemoteLifecycleListener.java 2017-01-18 09:40:32.291409357 -0500 +@@ -25,17 +25,25 @@ + import java.net.ServerSocket; + import java.net.Socket; + import java.net.UnknownHostException; ++import java.rmi.AlreadyBoundException; + import java.rmi.RemoteException; + import java.rmi.registry.LocateRegistry; ++import java.rmi.registry.Registry; + import java.rmi.server.RMIClientSocketFactory; + import java.rmi.server.RMIServerSocketFactory; ++import java.security.NoSuchAlgorithmException; ++import java.util.ArrayList; + import java.util.HashMap; ++import java.util.List; ++import java.util.Locale; + +-import javax.management.MBeanServer; + import javax.management.remote.JMXConnectorServer; +-import javax.management.remote.JMXConnectorServerFactory; + import javax.management.remote.JMXServiceURL; + import javax.management.remote.rmi.RMIConnectorServer; ++import javax.management.remote.rmi.RMIJRMPServerImpl; ++import javax.net.ssl.SSLContext; ++import javax.net.ssl.SSLServerSocket; ++import javax.net.ssl.SSLServerSocketFactory; + import javax.rmi.ssl.SslRMIClientSocketFactory; + import javax.rmi.ssl.SslRMIServerSocketFactory; + +@@ -55,19 +63,16 @@ + */ + public class JmxRemoteLifecycleListener implements LifecycleListener { + +- private static final Log log = +- LogFactory.getLog(JmxRemoteLifecycleListener.class); ++ private static final Log log = LogFactory.getLog(JmxRemoteLifecycleListener.class); + +- /** +- * The string resources for this package. +- */ + protected static final StringManager sm = +- StringManager.getManager(Constants.Package); ++ StringManager.getManager(Constants.Package); + + protected String rmiBindAddress = null; + protected int rmiRegistryPortPlatform = -1; + protected int rmiServerPortPlatform = -1; +- protected boolean rmiSSL = true; ++ protected boolean rmiRegistrySSL = true; ++ protected boolean rmiServerSSL = true; + protected String ciphers[] = null; + protected String protocols[] = null; + protected boolean clientAuth = true; +@@ -154,9 +159,13 @@ + // Get all the other parameters required from the standard system + // properties. Only need to get the parameters that affect the creation + // of the server port. +- String rmiSSLValue = System.getProperty( ++ String rmiRegistrySSLValue = System.getProperty( ++ "com.sun.management.jmxremote.registry.ssl", "false"); ++ rmiRegistrySSL = Boolean.parseBoolean(rmiRegistrySSLValue); ++ ++ String rmiServerSSLValue = System.getProperty( + "com.sun.management.jmxremote.ssl", "true"); +- rmiSSL = Boolean.parseBoolean(rmiSSLValue); ++ rmiServerSSL = Boolean.parseBoolean(rmiServerSSLValue); + + String protocolsValue = System.getProperty( + "com.sun.management.jmxremote.ssl.enabled.protocols"); +@@ -171,7 +180,7 @@ + } + + String clientAuthValue = System.getProperty( +- "com.sun.management.jmxremote.ssl.need.client.auth", "true"); ++ "com.sun.management.jmxremote.ssl.need.client.auth", "true"); + clientAuth = Boolean.parseBoolean(clientAuthValue); + + String authenticateValue = System.getProperty( +@@ -204,47 +213,64 @@ + // Create the environment + HashMap env = new HashMap(); + +- RMIClientSocketFactory csf = null; +- RMIServerSocketFactory ssf = null; ++ RMIClientSocketFactory registryCsf = null; ++ RMIServerSocketFactory registrySsf = null; ++ ++ RMIClientSocketFactory serverCsf = null; ++ RMIServerSocketFactory serverSsf = null; + +- // Configure SSL for RMI connection if required +- if (rmiSSL) { ++ // Configure registry socket factories ++ if (rmiRegistrySSL) { ++ registryCsf = new SslRMIClientSocketFactory(); ++ if (rmiBindAddress == null) { ++ registrySsf = new SslRMIServerSocketFactory( ++ ciphers, protocols, clientAuth); ++ } else { ++ registrySsf = new SslRmiServerBindSocketFactory( ++ ciphers, protocols, clientAuth, rmiBindAddress); ++ } ++ } else { + if (rmiBindAddress != null) { +- throw new IllegalStateException(sm.getString( +- "jmxRemoteLifecycleListener.sslRmiBindAddress")); ++ registrySsf = new RmiServerBindSocketFactory(rmiBindAddress); + } ++ } + +- csf = new SslRMIClientSocketFactory(); +- ssf = new SslRMIServerSocketFactory(ciphers, protocols, +- clientAuth); ++ // Configure server socket factories ++ if (rmiServerSSL) { ++ serverCsf = new SslRMIClientSocketFactory(); ++ if (rmiBindAddress == null) { ++ serverSsf = new SslRMIServerSocketFactory( ++ ciphers, protocols, clientAuth); ++ } else { ++ serverSsf = new SslRmiServerBindSocketFactory( ++ ciphers, protocols, clientAuth, rmiBindAddress); ++ } ++ } else { ++ if (rmiBindAddress != null) { ++ serverSsf = new RmiServerBindSocketFactory(rmiBindAddress); ++ } + } + +- // Force server bind address if required ++ // By default, the registry will pick an address to listen on. ++ // Setting this property overrides that and ensures it listens on ++ // the configured address. + if (rmiBindAddress != null) { +- try { +- ssf = new RmiServerBindSocketFactory( +- InetAddress.getByName(rmiBindAddress)); +- } catch (UnknownHostException e) { +- log.error(sm.getString( +- "jmxRemoteLifecycleListener.invalidRmiBindAddress", +- rmiBindAddress), e); +- } ++ System.setProperty("java.rmi.server.hostname", rmiBindAddress); + } + + // Force the use of local ports if required + if (useLocalPorts) { +- csf = new RmiClientLocalhostSocketFactory(csf); ++ registryCsf = new RmiClientLocalhostSocketFactory(registryCsf); ++ serverCsf = new RmiClientLocalhostSocketFactory(serverCsf); + } + + // Populate the env properties used to create the server +- if (csf != null) { +- env.put(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE, +- csf); +- env.put("com.sun.jndi.rmi.factory.socket", csf); +- } +- if (ssf != null) { +- env.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE, +- ssf); ++ if (serverCsf != null) { ++ env.put(RMIConnectorServer.RMI_CLIENT_SOCKET_FACTORY_ATTRIBUTE, serverCsf); ++ env.put("com.sun.jndi.rmi.factory.socket", registryCsf); ++ } ++ if (serverSsf != null) { ++ env.put(RMIConnectorServer.RMI_SERVER_SOCKET_FACTORY_ATTRIBUTE, serverSsf); + } + + // Configure authentication +@@ -254,25 +280,27 @@ + env.put("jmx.remote.x.login.config", loginModuleName); + } + +- + // Create the Platform server + csPlatform = createServer("Platform", rmiBindAddress, rmiRegistryPortPlatform, +- rmiServerPortPlatform, env, csf, ssf, +- ManagementFactory.getPlatformMBeanServer()); ++ rmiServerPortPlatform, env, registryCsf, registrySsf, serverCsf, serverSsf); + + } else if (Lifecycle.STOP_EVENT == event.getType()) { + destroyServer("Platform", csPlatform); + } + } + ++ + private JMXConnectorServer createServer(String serverName, + String bindAddress, int theRmiRegistryPort, int theRmiServerPort, +- HashMap theEnv, RMIClientSocketFactory csf, +- RMIServerSocketFactory ssf, MBeanServer theMBeanServer) { ++ HashMap theEnv, ++ RMIClientSocketFactory registryCsf, RMIServerSocketFactory registrySsf, ++ RMIClientSocketFactory serverCsf, RMIServerSocketFactory serverSsf) { + + // Create the RMI registry ++ Registry registry; + try { +- LocateRegistry.createRegistry(theRmiRegistryPort, csf, ssf); ++ registry = LocateRegistry.createRegistry( ++ theRmiRegistryPort, registryCsf, registrySsf); + } catch (RemoteException e) { + log.error(sm.getString( + "jmxRemoteLifecycleListener.createRegistryFailed", +@@ -284,33 +312,23 @@ + bindAddress = "localhost"; + } + +- // Build the connection string with fixed ports +- StringBuilder url = new StringBuilder(); +- url.append("service:jmx:rmi://"); +- url.append(bindAddress); +- url.append(":"); +- url.append(theRmiServerPort); +- url.append("/jndi/rmi://"); +- url.append(bindAddress); +- url.append(":"); +- url.append(theRmiRegistryPort); +- url.append("/jmxrmi"); ++ String url = "service:jmx:rmi://" + bindAddress; + JMXServiceURL serviceUrl; + try { + serviceUrl = new JMXServiceURL(url.toString()); + } catch (MalformedURLException e) { +- log.error(sm.getString( +- "jmxRemoteLifecycleListener.invalidURL", +- serverName, url.toString()), e); ++ log.error(sm.getString("jmxRemoteLifecycleListener.invalidURL", serverName, url), e); + return null; + } + +- // Start the JMX server with the connection string +- JMXConnectorServer cs = null; ++ RMIConnectorServer cs = null; + try { +- cs = JMXConnectorServerFactory.newJMXConnectorServer( +- serviceUrl, theEnv, theMBeanServer); ++ RMIJRMPServerImpl server = new RMIJRMPServerImpl( ++ rmiServerPortPlatform, serverCsf, serverSsf, theEnv); ++ cs = new RMIConnectorServer(serviceUrl, theEnv, server, ++ ManagementFactory.getPlatformMBeanServer()); + cs.start(); ++ registry.bind("jmxrmi", server); + log.info(sm.getString("jmxRemoteLifecycleListener.start", + Integer.toString(theRmiRegistryPort), + Integer.toString(theRmiServerPort), serverName)); +@@ -318,10 +336,15 @@ + log.error(sm.getString( + "jmxRemoteLifecycleListener.createServerFailed", + serverName), e); ++ } catch (AlreadyBoundException e) { ++ log.error(sm.getString( ++ "jmxRemoteLifecycleListener.createServerFailed", ++ serverName), e); + } + return cs; + } + ++ + private void destroyServer(String serverName, + JMXConnectorServer theConnectorServer) { + if (theConnectorServer != null) { +@@ -335,6 +358,7 @@ + } + } + ++ + public static class RmiClientLocalhostSocketFactory + implements RMIClientSocketFactory, Serializable { + +@@ -358,13 +382,22 @@ + } + } + +- public static class RmiServerBindSocketFactory +- implements RMIServerSocketFactory { ++ ++ public static class RmiServerBindSocketFactory implements RMIServerSocketFactory { + + private final InetAddress bindAddress; + +- public RmiServerBindSocketFactory(InetAddress address) { +- bindAddress = address; ++ public RmiServerBindSocketFactory(String address) { ++ InetAddress bindAddress = null; ++ try { ++ bindAddress = InetAddress.getByName(address); ++ } catch (UnknownHostException e) { ++ log.error(sm.getString( ++ "jmxRemoteLifecycleListener.invalidRmiBindAddress", address), e); ++ // bind address will be null which means any/all local addresses ++ // which should be safe ++ } ++ this.bindAddress = bindAddress; + } + + @Override +@@ -372,4 +405,64 @@ + return new ServerSocket(port, 0, bindAddress); + } + } ++ ++ ++ public static class SslRmiServerBindSocketFactory extends SslRMIServerSocketFactory { ++ ++ private static final SSLServerSocketFactory sslServerSocketFactory; ++ private static final String[] defaultProtocols; ++ ++ static { ++ SSLContext sslContext; ++ try { ++ sslContext = SSLContext.getDefault(); ++ } catch (NoSuchAlgorithmException e) { ++ // Can't continue. Force a failure. ++ throw new IllegalStateException(e); ++ } ++ sslServerSocketFactory = sslContext.getServerSocketFactory(); ++ String[] protocols = sslContext.getDefaultSSLParameters().getProtocols(); ++ List filteredProtocols = new ArrayList(protocols.length); ++ for (String protocol : protocols) { ++ if (protocol.toUpperCase(Locale.ENGLISH).contains("SSL")) { ++ continue; ++ } ++ filteredProtocols.add(protocol); ++ } ++ defaultProtocols = filteredProtocols.toArray(new String[filteredProtocols.size()]); ++ } ++ ++ private final InetAddress bindAddress; ++ ++ public SslRmiServerBindSocketFactory(String[] enabledCipherSuites, ++ String[] enabledProtocols, boolean needClientAuth, String address) { ++ super(enabledCipherSuites, enabledProtocols, needClientAuth); ++ InetAddress bindAddress = null; ++ try { ++ bindAddress = InetAddress.getByName(address); ++ } catch (UnknownHostException e) { ++ log.error(sm.getString( ++ "jmxRemoteLifecycleListener.invalidRmiBindAddress", address), e); ++ // bind address will be null which means any/all local addresses ++ // which should be safe ++ } ++ this.bindAddress = bindAddress; ++ } ++ ++ @Override ++ public ServerSocket createServerSocket(int port) throws IOException { ++ SSLServerSocket sslServerSocket = ++ (SSLServerSocket) sslServerSocketFactory.createServerSocket(port, 0, bindAddress); ++ if (getEnabledCipherSuites() != null) { ++ sslServerSocket.setEnabledCipherSuites(getEnabledCipherSuites()); ++ } ++ if (getEnabledProtocols() == null) { ++ sslServerSocket.setEnabledProtocols(defaultProtocols); ++ } else { ++ sslServerSocket.setEnabledProtocols(getEnabledProtocols()); ++ } ++ sslServerSocket.setNeedClientAuth(getNeedClientAuth()); ++ return sslServerSocket; ++ } ++ } + } +Index: tomcat7-7.0.52/java/org/apache/catalina/mbeans/LocalStrings.properties +=================================================================== +--- tomcat7-7.0.52.orig/java/org/apache/catalina/mbeans/LocalStrings.properties 2014-01-27 09:53:14.000000000 -0500 ++++ tomcat7-7.0.52/java/org/apache/catalina/mbeans/LocalStrings.properties 2017-01-18 09:40:32.291409357 -0500 +@@ -18,5 +18,4 @@ + jmxRemoteLifecycleListener.destroyServerFailed=The JMX connector server could not be stopped for the {0} server + jmxRemoteLifecycleListener.invalidURL=The JMX Service URL requested for the {0} server, "{1}", was invalid + jmxRemoteLifecycleListener.start=The JMX Remote Listener has configured the registry on port {0} and the server on port {1} for the {2} server +-jmxRemoteLifecycleListener.sslRmiBindAddress=rmiBindAddress is incompatible with setting the system property com.sun.management.jmxremote.ssl to true + jmxRemoteLifecycleListener.invalidRmiBindAddress=Invalid RMI bind address [{0}] +Index: tomcat7-7.0.52/webapps/docs/config/listeners.xml +=================================================================== +--- tomcat7-7.0.52.orig/webapps/docs/config/listeners.xml 2014-02-03 12:53:34.000000000 -0500 ++++ tomcat7-7.0.52/webapps/docs/config/listeners.xml 2017-01-18 09:40:32.291409357 -0500 +@@ -436,10 +436,7 @@ + + + +-

    The address of the interface to be used by JMX/RMI server. +- This option is incompatible with setting the system +- property com.sun.management.jmxremote.ssl to +- true.

    ++

    The address of the interface to be used by JMX/RMI server.

    +
    + + diff -Nru tomcat7-7.0.52/debian/patches/CVE-2016-8745.patch tomcat7-7.0.52/debian/patches/CVE-2016-8745.patch --- tomcat7-7.0.52/debian/patches/CVE-2016-8745.patch 1970-01-01 00:00:00.000000000 +0000 +++ tomcat7-7.0.52/debian/patches/CVE-2016-8745.patch 2017-01-19 17:51:34.000000000 +0000 @@ -0,0 +1,27 @@ +Description: fix information leakage between requests +Origin: backport, http://svn.apache.org/viewvc?view=revision&revision=1777471 +Bug-Debian: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=802312 +Bug: https://bz.apache.org/bugzilla/show_bug.cgi?id=60409 + +Index: tomcat7-7.0.52/java/org/apache/tomcat/util/net/NioEndpoint.java +=================================================================== +--- tomcat7-7.0.52.orig/java/org/apache/tomcat/util/net/NioEndpoint.java 2014-01-27 07:48:36.000000000 -0500 ++++ tomcat7-7.0.52/java/org/apache/tomcat/util/net/NioEndpoint.java 2017-01-18 09:41:58.600528200 -0500 +@@ -1379,11 +1379,15 @@ + } + }catch ( IOException x ) { + if ( log.isDebugEnabled() ) log.debug("Unable to complete sendfile request:", x); +- cancelledKey(sk,SocketStatus.ERROR,false); ++ if (!event) { ++ cancelledKey(sk,SocketStatus.ERROR,false); ++ } + return false; + }catch ( Throwable t ) { + log.error("",t); +- cancelledKey(sk, SocketStatus.ERROR, false); ++ if (!event) { ++ cancelledKey(sk, SocketStatus.ERROR, false); ++ } + return false; + }finally { + if (sc!=null) sc.setSendFile(false); diff -Nru tomcat7-7.0.52/debian/patches/series tomcat7-7.0.52/debian/patches/series --- tomcat7-7.0.52/debian/patches/series 2016-09-16 13:22:34.000000000 +0000 +++ tomcat7-7.0.52/debian/patches/series 2017-01-18 14:40:58.000000000 +0000 @@ -32,3 +32,12 @@ fix_cookie_names_in_tests.patch CVE-2016-3092.patch CVE-2015-5345-2.patch +CVE-2016-5018.patch +CVE-2016-5388.patch +CVE-2016-6794.patch +CVE-2016-6796.patch +CVE-2016-6797.patch +CVE-2016-6816.patch +CVE-2016-8735-pre.patch +CVE-2016-8735.patch +CVE-2016-8745.patch diff -Nru tomcat7-7.0.52/debian/rules tomcat7-7.0.52/debian/rules --- tomcat7-7.0.52/debian/rules 2014-02-21 06:11:51.000000000 +0000 +++ tomcat7-7.0.52/debian/rules 2017-01-19 17:32:36.000000000 +0000 @@ -191,6 +191,12 @@ jh_manifest dh_compress dh_fixperms + + # Make the /etc/tomcat7/Catalina/localhost directory writable by the tomcat user + for PACKAGE in tomcat7 tomcat7-admin tomcat7-docs tomcat7-examples; do \ + chmod 775 --verbose debian/$$PACKAGE/etc/tomcat7/Catalina/localhost; \ + done + dh_installdeb dh_gencontrol dh_md5sums diff -Nru tomcat7-7.0.52/debian/tomcat7.init tomcat7-7.0.52/debian/tomcat7.init --- tomcat7-7.0.52/debian/tomcat7.init 2016-09-16 13:20:03.000000000 +0000 +++ tomcat7-7.0.52/debian/tomcat7.init 2017-01-19 17:37:53.000000000 +0000 @@ -118,7 +118,7 @@ exit 1 fi -POLICY_CACHE="$CATALINA_BASE/work/catalina.policy" +POLICY_CACHE="$CATALINA_BASE/policy/catalina.policy" if [ -z "$CATALINA_TMPDIR" ]; then CATALINA_TMPDIR="$JVM_TMP" @@ -171,7 +171,8 @@ # Run the catalina.sh script as a daemon set +e if [ ! -f "$CATALINA_BASE"/logs/catalina.out ]; then - install -o $TOMCAT7_USER -g adm -m 644 /dev/null "$CATALINA_BASE"/logs/catalina.out + # run install as tomcat7 to work around #841371 + su $TOMCAT7_USER -s /bin/bash -c "install -m 644 /dev/null $CATALINA_BASE/logs/catalina.out" fi install -o $TOMCAT7_USER -g adm -m 644 /dev/null "$CATALINA_PID" start-stop-daemon --start -b -u "$TOMCAT7_USER" -g "$TOMCAT7_GROUP" \ @@ -201,6 +202,8 @@ # Regenerate POLICY_CACHE file umask 022 + rm -rf "$CATALINA_BASE/policy" + mkdir "$CATALINA_BASE/policy" echo "// AUTO-GENERATED FILE from /etc/tomcat7/policy.d/" \ > "$POLICY_CACHE" echo "" >> "$POLICY_CACHE" @@ -209,11 +212,11 @@ # Remove / recreate JVM_TMP directory rm -rf "$JVM_TMP" - mkdir -p "$JVM_TMP" || { + mkdir "$JVM_TMP" || { log_failure_msg "could not create JVM temporary directory" exit 1 } - chown $TOMCAT7_USER "$JVM_TMP" + chown -h $TOMCAT7_USER "$JVM_TMP" catalina_sh start $SECURITY sleep 5 diff -Nru tomcat7-7.0.52/debian/tomcat7.postinst tomcat7-7.0.52/debian/tomcat7.postinst --- tomcat7-7.0.52/debian/tomcat7.postinst 2014-02-21 06:11:51.000000000 +0000 +++ tomcat7-7.0.52/debian/tomcat7.postinst 2017-01-19 17:34:38.000000000 +0000 @@ -48,11 +48,28 @@ # configuration files should not be modifiable by tomcat7 user, as this can be a security issue # (an attacker may insert code in a webapp and have access to all tomcat configuration) # but those files should be readable by tomcat7, so we set the group to tomcat7 - chown -Rh root:$TOMCAT7_GROUP /etc/tomcat7/* - chmod 640 /etc/tomcat7/tomcat-users.xml + for i in tomcat-users.xml web.xml server.xml logging.properties context.xml catalina.properties; + do + if [ -f "/etc/tomcat7/$i" ]; then + chown root:$TOMCAT7_GROUP /etc/tomcat7/$i + chmod 640 /etc/tomcat7/$i + fi + done + # configuration policy files should not be modifiable by the tomcat7 user. Only + # diverge from default permissions for known Debian files + chown root:$TOMCAT7_GROUP /etc/tomcat7/policy.d + for i in 01system.policy 02debian.policy 03catalina.policy 04webapps.policy 50local.policy; + do + if [ -f "/etc/tomcat7/policy.d/$i" ]; then + chown root:$TOMCAT7_GROUP /etc/tomcat7/policy.d/$i + chmod 640 /etc/tomcat7/policy.d/$i + fi + done + chown -Rh root:$TOMCAT7_GROUP /etc/tomcat7/Catalina + chown -Rh $TOMCAT7_USER:$TOMCAT7_GROUP /var/lib/tomcat7/webapps /var/lib/tomcat7/common /var/lib/tomcat7/server /var/lib/tomcat7/shared chmod 775 /var/lib/tomcat7/webapps - chmod 775 /etc/tomcat7/Catalina /etc/tomcat7/Catalina/localhost + chmod 775 /etc/tomcat7/Catalina # Authorize user tomcat7 to open privileged ports via authbind. TOMCAT_UID="`id -u $TOMCAT7_USER`" diff -Nru tomcat7-7.0.52/debian/tomcat7.postrm.in tomcat7-7.0.52/debian/tomcat7.postrm.in --- tomcat7-7.0.52/debian/tomcat7.postrm.in 2014-02-21 06:11:51.000000000 +0000 +++ tomcat7-7.0.52/debian/tomcat7.postrm.in 2017-01-19 17:34:51.000000000 +0000 @@ -58,9 +58,6 @@ /etc/tomcat7/Catalina/localhost /etc/tomcat7/Catalina /etc/tomcat7 # clean up /etc/authbind after conffiles have been removed rmdir --ignore-fail-on-non-empty /etc/authbind/byuid /etc/authbind - # Put all files owned by group tomcat7 back into root group before deleting - # the tomcat7 user and group - chown -Rhf root:root /etc/tomcat7/ || true # Remove user/group and log files (don't remove everything under # /var/lib/tomcat7 because there might be user-installed webapps) db_get tomcat7/username && TOMCAT7_USER="$RET" || TOMCAT7_USER="tomcat7"