[tomcat8] 01/01: Import security fixes for Jessie
Markus Koschany
apo at moszumanska.debian.org
Wed Jun 22 15:58:23 UTC 2016
This is an automated email from the git hooks/post-receive script.
apo pushed a commit to branch jessie
in repository tomcat8.
commit 4772709a1b7bacd11995e534ebad608e4e0882c0
Author: Markus Koschany <apo at debian.org>
Date: Wed Jun 22 17:57:25 2016 +0200
Import security fixes for Jessie
---
debian/changelog | 47 +++
debian/patches/CVE-2015-5174.patch | 249 +++++++++++++
debian/patches/CVE-2015-5345.patch | 535 +++++++++++++++++++++++++++
debian/patches/CVE-2015-5346.patch | 142 +++++++
debian/patches/CVE-2015-5351.patch | 112 ++++++
debian/patches/CVE-2016-0706.patch | 34 ++
debian/patches/CVE-2016-0714.patch | 731 +++++++++++++++++++++++++++++++++++++
debian/patches/CVE-2016-0763.patch | 41 +++
debian/patches/series | 7 +
9 files changed, 1898 insertions(+)
diff --git a/debian/changelog b/debian/changelog
index 348758b..b05f5b7 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,50 @@
+tomcat8 (8.0.14-1+deb8u2) jessie-security; urgency=high
+
+ * Team upload.
+ * Fix CVE-2015-5174:
+ Directory traversal vulnerability in RequestUtil.java allows remote
+ authenticated users to bypass intended SecurityManager restrictions and
+ list a parent directory via a /.. (slash dot dot) in a pathname used by a
+ web application in a getResource, getResourceAsStream, or getResourcePaths
+ call, as demonstrated by the $CATALINA_BASE/webapps directory.
+ * Fix CVE-2015-5345:
+ The Mapper component in Apache Tomcat processes redirects before
+ considering security constraints and Filters, which allows remote attackers
+ to determine the existence of a directory via a URL that lacks a trailing /
+ (slash) character.
+ * Fix CVE-2015-5346:
+ Session fixation vulnerability in Apache Tomcat when different session
+ settings are used for deployments of multiple versions of the same web
+ application, might allow remote attackers to hijack web sessions by
+ leveraging use of a requestedSessionSSL field for an unintended request,
+ related to CoyoteAdapter.java and Request.java.
+ * Fix CVE-2015-5351:
+ The Manager and Host Manager applications in Apache Tomcat establish
+ sessions and send CSRF tokens for arbitrary new requests, which allows
+ remote attackers to bypass a CSRF protection mechanism by using a token.
+ * Fix CVE-2016-0706:
+ Apache Tomcat does not place
+ org.apache.catalina.manager.StatusManagerServlet on the
+ org/apache/catalina/core/RestrictedServlets.properties list, which allows
+ remote authenticated users to bypass intended SecurityManager restrictions
+ and read arbitrary HTTP requests, and consequently discover session ID
+ values, via a crafted web application.
+ * Fix CVE-2016-0714:
+ The session-persistence implementation in Apache Tomcat mishandles session
+ attributes, which allows remote authenticated users to bypass intended
+ SecurityManager restrictions and execute arbitrary code in a privileged
+ context via a web application that places a crafted object in a session.
+ * Fix CVE-2016-0763:
+ The setGlobalContext method in
+ org/apache/naming/factory/ResourceLinkFactory.java in Apache Tomcat does
+ not consider whether ResourceLinkFactory.setGlobalContext callers are
+ authorized, which allows remote authenticated users to bypass intended
+ SecurityManager restrictions and read or write to arbitrary application
+ data, or cause a denial of service (application disruption), via a web
+ application that sets a crafted global context.
+
+ -- Markus Koschany <apo at debian.org> Sun, 29 May 2016 23:11:52 +0200
+
tomcat8 (8.0.14-1+deb8u1) jessie-security; urgency=medium
* Fixed CVE-2014-7810: Malicious web applications could use expression
diff --git a/debian/patches/CVE-2015-5174.patch b/debian/patches/CVE-2015-5174.patch
new file mode 100644
index 0000000..19ffa3b
--- /dev/null
+++ b/debian/patches/CVE-2015-5174.patch
@@ -0,0 +1,249 @@
+From: Markus Koschany <apo at debian.org>
+Date: Sat, 28 May 2016 01:54:08 +0000
+Subject: CVE-2015-5174
+
+Origin: https://svn.apache.org/viewvc?view=revision&revision=1696281
+Origin: https://svn.apache.org/viewvc?view=revision&revision=1700897
+---
+ java/org/apache/tomcat/util/http/RequestUtil.java | 45 ++++++----
+ .../apache/tomcat/util/http/TestRequestUtil.java | 100 +++++++++++++++++++--
+ webapps/docs/changelog.xml | 11 +++
+ 3 files changed, 135 insertions(+), 21 deletions(-)
+
+diff --git a/java/org/apache/tomcat/util/http/RequestUtil.java b/java/org/apache/tomcat/util/http/RequestUtil.java
+index ebe4f34..1ee4bca 100644
+--- a/java/org/apache/tomcat/util/http/RequestUtil.java
++++ b/java/org/apache/tomcat/util/http/RequestUtil.java
+@@ -30,6 +30,9 @@ public class RequestUtil {
+ * try to perform security checks for malicious input.
+ *
+ * @param path Relative path to be normalized
++ *
++ * @return The normalized path or <code>null</code> of the path cannot be
++ * normalized
+ */
+ public static String normalize(String path) {
+ return normalize(path, true);
+@@ -44,11 +47,15 @@ public class RequestUtil {
+ *
+ * @param path Relative path to be normalized
+ * @param replaceBackSlash Should '\\' be replaced with '/'
++ *
++ * @return The normalized path or <code>null</code> of the path cannot be
++ * normalized
+ */
+ public static String normalize(String path, boolean replaceBackSlash) {
+
+- if (path == null)
++ if (path == null) {
+ return null;
++ }
+
+ // Create a place for the normalized path
+ String normalized = path;
+@@ -56,9 +63,6 @@ public class RequestUtil {
+ if (replaceBackSlash && normalized.indexOf('\\') >= 0)
+ normalized = normalized.replace('\\', '/');
+
+- if (normalized.equals("/."))
+- return "/";
+-
+ // Add a leading "/" if necessary
+ if (!normalized.startsWith("/"))
+ normalized = "/" + normalized;
+@@ -66,34 +70,43 @@ public class RequestUtil {
+ // Resolve occurrences of "//" in the normalized path
+ while (true) {
+ int index = normalized.indexOf("//");
+- if (index < 0)
++ if (index < 0) {
+ break;
+- normalized = normalized.substring(0, index) +
+- normalized.substring(index + 1);
++ }
++ normalized = normalized.substring(0, index) + normalized.substring(index + 1);
+ }
+
+ // Resolve occurrences of "/./" in the normalized path
+ while (true) {
+ int index = normalized.indexOf("/./");
+- if (index < 0)
++ if (index < 0) {
+ break;
+- normalized = normalized.substring(0, index) +
+- normalized.substring(index + 2);
++ }
++ normalized = normalized.substring(0, index) + normalized.substring(index + 2);
+ }
+
+ // Resolve occurrences of "/../" in the normalized path
+ while (true) {
+ int index = normalized.indexOf("/../");
+- if (index < 0)
++ if (index < 0) {
+ break;
+- if (index == 0)
+- return (null); // Trying to go outside our context
++ }
++ if (index == 0) {
++ return null; // Trying to go outside our context
++ }
+ int index2 = normalized.lastIndexOf('/', index - 1);
+- normalized = normalized.substring(0, index2) +
+- normalized.substring(index + 3);
++ normalized = normalized.substring(0, index2) + normalized.substring(index + 3);
++ }
++
++ if (normalized.equals("/.")) {
++ return "/";
++ }
++
++ if (normalized.equals("/..")) {
++ return null; // Trying to go outside our context
+ }
+
+ // Return the normalized path that we have completed
+- return (normalized);
++ return normalized;
+ }
+ }
+diff --git a/test/org/apache/tomcat/util/http/TestRequestUtil.java b/test/org/apache/tomcat/util/http/TestRequestUtil.java
+index fe3115f..f50098c 100644
+--- a/test/org/apache/tomcat/util/http/TestRequestUtil.java
++++ b/test/org/apache/tomcat/util/http/TestRequestUtil.java
+@@ -23,11 +23,101 @@ import org.junit.Test;
+ public class TestRequestUtil {
+
+ @Test
+- public void testNormalizeString() {
+- assertEquals("/something",RequestUtil.normalize("//something"));
+- assertEquals("/some/thing",RequestUtil.normalize("some//thing"));
+- assertEquals("/something/",RequestUtil.normalize("something//"));
+- assertEquals("/",RequestUtil.normalize("//"));
++ public void testNormalize01() {
++ doTestNormalize("//something", "/something");
+ }
+
++ @Test
++ public void testNormalize02() {
++ doTestNormalize("some//thing", "/some/thing");
++ }
++
++ @Test
++ public void testNormalize03() {
++ doTestNormalize("something//", "/something/");
++ }
++
++ @Test
++ public void testNormalize04() {
++ doTestNormalize("//", "/");
++ }
++
++ @Test
++ public void testNormalize05() {
++ doTestNormalize("//", "/");
++ }
++
++ @Test
++ public void testNormalize06() {
++ doTestNormalize("///", "/");
++ }
++
++ @Test
++ public void testNormalize07() {
++ doTestNormalize("////", "/");
++ }
++
++ @Test
++ public void testNormalize08() {
++ doTestNormalize("/.", "/");
++ }
++
++ @Test
++ public void testNormalize09() {
++ doTestNormalize("/./", "/");
++ }
++
++ @Test
++ public void testNormalize10() {
++ doTestNormalize(".", "/");
++ }
++
++ @Test
++ public void testNormalize11() {
++ doTestNormalize("/..", null);
++ }
++
++ @Test
++ public void testNormalize12() {
++ doTestNormalize("/../", null);
++ }
++
++ @Test
++ public void testNormalize13() {
++ doTestNormalize("..", null);
++ }
++
++ @Test
++ public void testNormalize14() {
++ doTestNormalize("//..", null);
++ }
++
++ @Test
++ public void testNormalize15() {
++ doTestNormalize("//../", null);
++ }
++
++ @Test
++ public void testNormalize16() {
++ doTestNormalize("/./..", null);
++ }
++
++ @Test
++ public void testNormalize17() {
++ doTestNormalize("/./../", null);
++ }
++
++ @Test
++ public void testNormalize18() {
++ doTestNormalize("/a/../..", null);
++ }
++
++ @Test
++ public void testNormalize19() {
++ doTestNormalize("/a/../../", null);
++ }
++
++ private void doTestNormalize(String input, String expected) {
++ assertEquals(expected,RequestUtil.normalize(input));
++ }
+ }
+diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
+index a89b75e..f552c88 100644
+--- a/webapps/docs/changelog.xml
++++ b/webapps/docs/changelog.xml
+@@ -1857,6 +1857,10 @@
+ Enable non-blocking reads to take place on non-container threads.
+ (markt)
+ </fix>
++ <fix>
++ Correct a coupe of edge cases in <code>RequestUtil.normalize()</code>.
++ (markt)
++ </fix>
+ </changelog>
+ </subsection>
+ <subsection name="Cluster">
+@@ -1868,6 +1872,13 @@
+ </scode>
+ </changelog>
+ </subsection>
++ <subsection name="Coyote">
++ <changelog>
++ <fix>
++ Correct some edge cases in <code>RequestUtil.normalize()</code>. (markt)
++ </fix>
++ </changelog>
++ </subsection>
+ <subsection name="Web applications">
+ <changelog>
+ <fix>
diff --git a/debian/patches/CVE-2015-5345.patch b/debian/patches/CVE-2015-5345.patch
new file mode 100644
index 0000000..dc39b90
--- /dev/null
+++ b/debian/patches/CVE-2015-5345.patch
@@ -0,0 +1,535 @@
+From: Markus Koschany <apo at debian.org>
+Date: Sun, 29 May 2016 18:09:44 +0200
+Subject: CVE-2015-5345
+
+Origin: https://svn.apache.org/viewvc?view=revision&revision=1715207
+Origin: https://svn.apache.org/viewvc?view=revision&revision=1717209
+---
+ java/org/apache/catalina/Context.java | 40 ++++++++++++++
+ .../catalina/authenticator/FormAuthenticator.java | 14 +++++
+ java/org/apache/catalina/core/StandardContext.java | 35 ++++++++++++
+ .../apache/catalina/core/mbeans-descriptors.xml | 8 +++
+ java/org/apache/catalina/mapper/Mapper.java | 31 ++++++-----
+ .../apache/catalina/servlets/DefaultServlet.java | 28 +++++++++-
+ .../apache/catalina/servlets/WebdavServlet.java | 5 ++
+ .../org/apache/catalina/startup/FailedContext.java | 19 ++++++-
+ test/org/apache/catalina/core/TesterContext.java | 17 ++++++
+ .../apache/catalina/mapper/TestMapperWebapps.java | 64 ++++++++++++++++++++++
+ .../apache/catalina/startup/TomcatBaseTest.java | 3 +-
+ webapps/docs/changelog.xml | 15 +++++
+ webapps/docs/config/context.xml | 16 ++++++
+ 13 files changed, 276 insertions(+), 19 deletions(-)
+
+diff --git a/java/org/apache/catalina/Context.java b/java/org/apache/catalina/Context.java
+index a871b99..84c2a60 100644
+--- a/java/org/apache/catalina/Context.java
++++ b/java/org/apache/catalina/Context.java
+@@ -1674,4 +1674,44 @@ public interface Context extends Container {
+ * processing cookies using the RFC6265 based cookie parser.
+ */
+ public Charset getCookieEncodingCharset();
++
++ /**
++ * If enabled, requests for a web application context root will be
++ * redirected (adding a trailing slash) by the Mapper. This is more
++ * efficient but has the side effect of confirming that the context path is
++ * valid.
++ *
++ * @param mapperContextRootRedirectEnabled Should the redirects be enabled?
++ */
++ public void setMapperContextRootRedirectEnabled(boolean mapperContextRootRedirectEnabled);
++
++ /**
++ * Determines if requests for a web application context root will be
++ * redirected (adding a trailing slash) by the Mapper. This is more
++ * efficient but has the side effect of confirming that the context path is
++ * valid.
++ *
++ * @return {@code true} if the Mapper level redirect is enabled for this
++ * Context.
++ */
++ public boolean getMapperContextRootRedirectEnabled();
++
++ /**
++ * If enabled, requests for a directory will be redirected (adding a
++ * trailing slash) by the Mapper. This is more efficient but has the
++ * side effect of confirming that the directory is valid.
++ *
++ * @param mapperDirectoryRedirectEnabled Should the redirects be enabled?
++ */
++ public void setMapperDirectoryRedirectEnabled(boolean mapperDirectoryRedirectEnabled);
++
++ /**
++ * Determines if requests for a directory will be redirected (adding a
++ * trailing slash) by the Mapper. This is more efficient but has the
++ * side effect of confirming that the directory is valid.
++ *
++ * @return {@code true} if the Mapper level redirect is enabled for this
++ * Context.
++ */
++ public boolean getMapperDirectoryRedirectEnabled();
+ }
+diff --git a/java/org/apache/catalina/authenticator/FormAuthenticator.java b/java/org/apache/catalina/authenticator/FormAuthenticator.java
+index 57a3cd7..4933d03 100644
+--- a/java/org/apache/catalina/authenticator/FormAuthenticator.java
++++ b/java/org/apache/catalina/authenticator/FormAuthenticator.java
+@@ -241,6 +241,20 @@ public class FormAuthenticator
+
+ // No -- Save this request and redirect to the form login page
+ if (!loginAction) {
++ // If this request was to the root of the context without a trailing
++ // '/', need to redirect to add it else the submit of the login form
++ // may not go to the correct web application
++ if (request.getServletPath().length() == 0 && request.getPathInfo() == null) {
++ StringBuilder location = new StringBuilder(requestURI);
++ location.append('/');
++ if (request.getQueryString() != null) {
++ location.append('?');
++ location.append(request.getQueryString());
++ }
++ response.sendRedirect(response.encodeRedirectURL(location.toString()));
++ return false;
++ }
++
+ session = request.getSessionInternal(true);
+ if (log.isDebugEnabled()) {
+ log.debug("Save request in session '" + session.getIdInternal() + "'");
+diff --git a/java/org/apache/catalina/core/StandardContext.java b/java/org/apache/catalina/core/StandardContext.java
+index f47dd3f..0615e26 100644
+--- a/java/org/apache/catalina/core/StandardContext.java
++++ b/java/org/apache/catalina/core/StandardContext.java
+@@ -828,9 +828,44 @@ public class StandardContext extends ContainerBase
+ private boolean useRfc6265 = false;
+ private Charset cookieEncoding = StandardCharsets.UTF_8;
+
++ boolean mapperContextRootRedirectEnabled = false;
++ boolean mapperDirectoryRedirectEnabled = false;
+
+ // ----------------------------------------------------- Context Properties
+
++ @Override
++ public void setMapperContextRootRedirectEnabled(boolean mapperContextRootRedirectEnabled) {
++ this.mapperContextRootRedirectEnabled = mapperContextRootRedirectEnabled;
++ }
++
++
++ /**
++ * {@inheritDoc}
++ * <p>
++ * The default value for this implementation is {@code false}.
++ */
++ @Override
++ public boolean getMapperContextRootRedirectEnabled() {
++ return mapperContextRootRedirectEnabled;
++ }
++
++
++ @Override
++ public void setMapperDirectoryRedirectEnabled(boolean mapperDirectoryRedirectEnabled) {
++ this.mapperDirectoryRedirectEnabled = mapperDirectoryRedirectEnabled;
++ }
++
++
++ /**
++ * {@inheritDoc}
++ * <p>
++ * The default value for this implementation is {@code false}.
++ */
++ @Override
++ public boolean getMapperDirectoryRedirectEnabled() {
++ return mapperDirectoryRedirectEnabled;
++ }
++
+
+ @Override
+ public void setUseRfc6265(boolean useRfc6265) {
+diff --git a/java/org/apache/catalina/core/mbeans-descriptors.xml b/java/org/apache/catalina/core/mbeans-descriptors.xml
+index 64fe285..27847bf 100644
+--- a/java/org/apache/catalina/core/mbeans-descriptors.xml
++++ b/java/org/apache/catalina/core/mbeans-descriptors.xml
+@@ -181,6 +181,14 @@
+ description="Associated manager."
+ type="org.apache.catalina.Manager" />
+
++ <attribute name="mapperContextRootRedirectEnabled"
++ description="Should the Mapper be used for context root redirects"
++ type="boolean" />
++
++ <attribute name="mapperDirectoryRedirectEnabled"
++ description="Should the Mapper be used for directory redirects"
++ type="boolean" />
++
+ <attribute name="namingContextListener"
+ description="Associated naming context listener."
+ type="org.apache.catalina.core.NamingContextListener" />
+diff --git a/java/org/apache/catalina/mapper/Mapper.java b/java/org/apache/catalina/mapper/Mapper.java
+index a40b257..0c57145 100644
+--- a/java/org/apache/catalina/mapper/Mapper.java
++++ b/java/org/apache/catalina/mapper/Mapper.java
+@@ -830,20 +830,13 @@ public final class Mapper {
+
+ int pathOffset = path.getOffset();
+ int pathEnd = path.getEnd();
+- int servletPath = pathOffset;
+ boolean noServletPath = false;
+
+ int length = contextVersion.path.length();
+- if (length != (pathEnd - pathOffset)) {
+- servletPath = pathOffset + length;
+- } else {
++ if (length == (pathEnd - pathOffset)) {
+ noServletPath = true;
+- path.append('/');
+- pathOffset = path.getOffset();
+- pathEnd = path.getEnd();
+- servletPath = pathOffset+length;
+ }
+-
++ int servletPath = pathOffset + length;
+ path.setOffset(servletPath);
+
+ // Rule 1 -- Exact Match
+@@ -878,10 +871,13 @@ public final class Mapper {
+ }
+ }
+
+- if(mappingData.wrapper == null && noServletPath) {
++ if(mappingData.wrapper == null && noServletPath &&
++ mappingData.context.getMapperContextRootRedirectEnabled()) {
+ // The path is empty, redirect to "/"
++ path.append('/');
++ pathEnd = path.getEnd();
+ mappingData.redirectPath.setChars
+- (path.getBuffer(), pathOffset, pathEnd-pathOffset);
++ (path.getBuffer(), pathOffset, pathEnd - pathOffset);
+ path.setEnd(pathEnd - 1);
+ return;
+ }
+@@ -996,9 +992,15 @@ public final class Mapper {
+ char[] buf = path.getBuffer();
+ if (contextVersion.resources != null && buf[pathEnd -1 ] != '/') {
+ String pathStr = path.toString();
+- WebResource file =
+- contextVersion.resources.getResource(pathStr);
+- if (file != null && file.isDirectory()) {
++ WebResource file;
++ // Handle context root
++ if (pathStr.length() == 0) {
++ file = contextVersion.resources.getResource("/");
++ } else {
++ file = contextVersion.resources.getResource(pathStr);
++ }
++ if (file != null && file.isDirectory() &&
++ mappingData.context.getMapperDirectoryRedirectEnabled()) {
+ // Note: this mutates the path: do not do any processing
+ // after this (since we set the redirectPath, there
+ // shouldn't be any)
+@@ -1015,7 +1017,6 @@ public final class Mapper {
+
+ path.setOffset(pathOffset);
+ path.setEnd(pathEnd);
+-
+ }
+
+
+diff --git a/java/org/apache/catalina/servlets/DefaultServlet.java b/java/org/apache/catalina/servlets/DefaultServlet.java
+index cbf65b6..021425c 100644
+--- a/java/org/apache/catalina/servlets/DefaultServlet.java
++++ b/java/org/apache/catalina/servlets/DefaultServlet.java
+@@ -342,6 +342,10 @@ public class DefaultServlet extends HttpServlet {
+ * @param request The servlet request we are processing
+ */
+ protected String getRelativePath(HttpServletRequest request) {
++ return getRelativePath(request, false);
++ }
++
++ protected String getRelativePath(HttpServletRequest request, boolean allowEmptyPath) {
+ // IMPORTANT: DefaultServlet can be mapped to '/' or '/path/*' but always
+ // serves resources from the web app root with context rooted paths.
+ // i.e. it can not be used to mount the web app root under a sub-path
+@@ -703,7 +707,8 @@ public class DefaultServlet extends HttpServlet {
+ boolean serveContent = content;
+
+ // Identify the requested resource path
+- String path = getRelativePath(request);
++ String path = getRelativePath(request, true);
++
+ if (debug > 0) {
+ if (serveContent)
+ log("DefaultServlet.serveResource: Serving resource '" +
+@@ -713,6 +718,12 @@ public class DefaultServlet extends HttpServlet {
+ path + "' headers only");
+ }
+
++ if (path.length() == 0) {
++ // Context root redirect
++ doDirectoryRedirect(request, response);
++ return;
++ }
++
+ WebResource resource = resources.getResource(path);
+
+ if (!resource.exists()) {
+@@ -827,6 +838,11 @@ public class DefaultServlet extends HttpServlet {
+ long contentLength = -1L;
+
+ if (resource.isDirectory()) {
++ if (!path.endsWith("/")) {
++ doDirectoryRedirect(request, response);
++ return;
++ }
++
+ // Skip directory listings if we have been configured to
+ // suppress them
+ if (!listings) {
+@@ -1032,6 +1048,16 @@ public class DefaultServlet extends HttpServlet {
+ }
+ }
+
++ private void doDirectoryRedirect(HttpServletRequest request, HttpServletResponse response)
++ throws IOException {
++ StringBuilder location = new StringBuilder(request.getRequestURI());
++ location.append('/');
++ if (request.getQueryString() != null) {
++ location.append('?');
++ location.append(request.getQueryString());
++ }
++ response.sendRedirect(response.encodeRedirectURL(location.toString()));
++ }
+
+ /**
+ * Parse the content-range header.
+diff --git a/java/org/apache/catalina/servlets/WebdavServlet.java b/java/org/apache/catalina/servlets/WebdavServlet.java
+index 7bccf76..1303d99 100644
+--- a/java/org/apache/catalina/servlets/WebdavServlet.java
++++ b/java/org/apache/catalina/servlets/WebdavServlet.java
+@@ -375,6 +375,11 @@ public class WebdavServlet
+ */
+ @Override
+ protected String getRelativePath(HttpServletRequest request) {
++ return getRelativePath(request, false);
++ }
++
++ @Override
++ protected String getRelativePath(HttpServletRequest request, boolean allowEmptyPath) {
+ // Are we being processed by a RequestDispatcher.include()?
+ if (request.getAttribute(
+ RequestDispatcher.INCLUDE_REQUEST_URI) != null) {
+diff --git a/java/org/apache/catalina/startup/FailedContext.java b/java/org/apache/catalina/startup/FailedContext.java
+index 73c6bf4..166ab45 100644
+--- a/java/org/apache/catalina/startup/FailedContext.java
++++ b/java/org/apache/catalina/startup/FailedContext.java
+@@ -771,4 +771,21 @@ public class FailedContext extends LifecycleMBeanBase implements Context {
+
+ @Override
+ public Charset getCookieEncodingCharset() { return StandardCharsets.UTF_8; }
+-}
+\ No newline at end of file
++
++ @Override
++ public void setMapperContextRootRedirectEnabled(boolean mapperContextRootRedirectEnabled) {
++ // NO-OP
++ }
++
++ @Override
++ public boolean getMapperContextRootRedirectEnabled() { return false; }
++
++ @Override
++ public void setMapperDirectoryRedirectEnabled(boolean mapperDirectoryRedirectEnabled) {
++ // NO-OP
++ }
++
++ @Override
++ public boolean getMapperDirectoryRedirectEnabled() { return false; }
++
++}
+diff --git a/test/org/apache/catalina/core/TesterContext.java b/test/org/apache/catalina/core/TesterContext.java
+index ac4d945..36bfdfe 100644
+--- a/test/org/apache/catalina/core/TesterContext.java
++++ b/test/org/apache/catalina/core/TesterContext.java
+@@ -1238,4 +1238,21 @@ public class TesterContext implements Context {
+
+ @Override
+ public Charset getCookieEncodingCharset() { return StandardCharsets.UTF_8; }
++
++ @Override
++ public void setMapperContextRootRedirectEnabled(boolean mapperContextRootRedirectEnabled) {
++ // NO-OP
++ }
++
++ @Override
++ public boolean getMapperContextRootRedirectEnabled() { return false; }
++
++ @Override
++ public void setMapperDirectoryRedirectEnabled(boolean mapperDirectoryRedirectEnabled) {
++ // NO-OP
++ }
++
++ @Override
++ public boolean getMapperDirectoryRedirectEnabled() { return false; }
++
+ }
+diff --git a/test/org/apache/catalina/mapper/TestMapperWebapps.java b/test/org/apache/catalina/mapper/TestMapperWebapps.java
+index 9014efd..3778fdf 100644
+--- a/test/org/apache/catalina/mapper/TestMapperWebapps.java
++++ b/test/org/apache/catalina/mapper/TestMapperWebapps.java
+@@ -18,6 +18,7 @@ package org.apache.catalina.mapper;
+
+ import java.io.File;
+ import java.io.IOException;
++import java.net.HttpURLConnection;
+ import java.util.HashMap;
+ import java.util.List;
+
+@@ -33,7 +34,10 @@ import org.apache.catalina.Context;
+ import org.apache.catalina.core.StandardContext;
+ import org.apache.catalina.startup.Tomcat;
+ import org.apache.catalina.startup.TomcatBaseTest;
++import org.apache.catalina.valves.RemoteAddrValve;
+ import org.apache.tomcat.util.buf.ByteChunk;
++import org.apache.tomcat.util.descriptor.web.SecurityCollection;
++import org.apache.tomcat.util.descriptor.web.SecurityConstraint;
+ import org.apache.tomcat.websocket.server.WsContextListener;
+
+ /**
+@@ -226,6 +230,66 @@ public class TestMapperWebapps extends TomcatBaseTest{
+ Assert.assertEquals(HttpServletResponse.SC_NOT_FOUND, rc);
+ }
+
++ @Test
++ public void testRedirect() throws Exception {
++ // Disable the following of redirects for this test only
++ boolean originalValue = HttpURLConnection.getFollowRedirects();
++ HttpURLConnection.setFollowRedirects(false);
++ try {
++ Tomcat tomcat = getTomcatInstance();
++
++ // Use standard test webapp as ROOT
++ File rootDir = new File("test/webapp");
++ org.apache.catalina.Context root =
++ tomcat.addWebapp(null, "", rootDir.getAbsolutePath());
++
++ // Add a security constraint
++ SecurityConstraint constraint = new SecurityConstraint();
++ SecurityCollection collection = new SecurityCollection();
++ collection.addPattern("/welcome-files/*");
++ collection.addPattern("/welcome-files");
++ constraint.addCollection(collection);
++ constraint.addAuthRole("foo");
++ root.addConstraint(constraint);
++
++ // Also make examples available
++ File examplesDir = new File(getBuildDirectory(), "webapps/examples");
++ org.apache.catalina.Context examples = tomcat.addWebapp(
++ null, "/examples", examplesDir.getAbsolutePath());
++ // Then block access to the examples to test redirection
++ RemoteAddrValve rav = new RemoteAddrValve();
++ rav.setDeny(".*");
++ rav.setDenyStatus(404);
++ examples.getPipeline().addValve(rav);
++
++ tomcat.start();
++
++ // Redirects within a web application
++ doRedirectTest("/welcome-files", 401);
++ doRedirectTest("/welcome-files/", 401);
++
++ doRedirectTest("/jsp", 302);
++ doRedirectTest("/jsp/", 404);
++
++ doRedirectTest("/WEB-INF", 404);
++ doRedirectTest("/WEB-INF/", 404);
++
++ // Redirects between web applications
++ doRedirectTest("/examples", 404);
++ doRedirectTest("/examples/", 404);
++ } finally {
++ HttpURLConnection.setFollowRedirects(originalValue);
++ }
++ }
++
++
++ private void doRedirectTest(String path, int expected) throws IOException {
++ ByteChunk bc = new ByteChunk();
++ int rc = getUrl("http://localhost:" + getPort() + path, bc, null);
++ Assert.assertEquals(expected, rc);
++ }
++
++
+ /**
+ * Prepare a string to search in messages that contain a timestamp, when it
+ * is known that the timestamp was printed between {@code timeA} and
+diff --git a/test/org/apache/catalina/startup/TomcatBaseTest.java b/test/org/apache/catalina/startup/TomcatBaseTest.java
+index 2808317..0856ea6 100644
+--- a/test/org/apache/catalina/startup/TomcatBaseTest.java
++++ b/test/org/apache/catalina/startup/TomcatBaseTest.java
+@@ -233,8 +233,7 @@ public abstract class TomcatBaseTest extends LoggingBaseTest {
+ String method) throws IOException {
+
+ URL url = new URL(path);
+- HttpURLConnection connection =
+- (HttpURLConnection) url.openConnection();
++ HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+ connection.setUseCaches(false);
+ connection.setReadTimeout(readTimeout);
+ connection.setRequestMethod(method);
+diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
+index a0b4788..02762a0 100644
+--- a/webapps/docs/changelog.xml
++++ b/webapps/docs/changelog.xml
+@@ -188,6 +188,16 @@
+ <bug>58809</bug>: Correctly recycle cookies when mapping requests for
+ parallel deployment. (markt)
+ </fix>
++ <add>
++ Move the functionality that provides redirects for context roots and
++ directories where a trailing <code>/</code> is added from the Mapper to
++ the <code>DefaultServlet</code>. This enables such requests to be
++ processed by any configured Valves and Filters before the redirect is
++ made. This behaviour is configurable via the
++ <code>mapperContextRootRedirectEnabled</code> and
++ <code>mapperDirectoryRedirectEnabled</code> attributes of the Context
++ which may be used to restore the previous behaviour. (markt)
++ </add>
+ </changelog>
+ </subsection>
+ <subsection name="Jasper">
+@@ -279,6 +289,11 @@
+ leak fixes and support for application provided eviction policies.
+ (markt)
+ </fix>
++ <fix>
++ <bug>58660</bug>: Correct a regression in 8.0.29 caused by the change
++ that moved the redirection for context roots from the Mapper to the
++ Default Servlet. (markt)
++ </fix>
+ </changelog>
+ </subsection>
+ </section>
+diff --git a/webapps/docs/config/context.xml b/webapps/docs/config/context.xml
+index 41e66ae..91634f0 100644
+--- a/webapps/docs/config/context.xml
++++ b/webapps/docs/config/context.xml
+@@ -367,6 +367,22 @@
+ default value of <code>false</code> is used.</p>
+ </attribute>
+
++ <attribute name="mapperContextRootRedirectEnabled" required="false">
++ <p>If enabled, requests for a web application context root will be
++ redirected (adding a trailing slash) if necessary by the Mapper rather
++ than the default Servlet. This is more efficient but has the side effect
++ of confirming that the context path exists. If not specified, the
++ default value of <code>false</code> is used.</p>
++ </attribute>
++
++ <attribute name="mapperDirectoryRedirectEnabled" required="false">
++ <p>If enabled, requests for a web application directory will be
++ redirected (adding a trailing slash) if necessary by the Mapper rather
++ than the default Servlet. This is more efficient but has the side effect
++ of confirming that the directory is exists. If not specified, the
++ default value of <code>false</code> is used.</p>
++ </attribute>
++
+ <attribute name="override" required="false">
+ <p>Set to <code>true</code> to ignore any settings in both the global
+ or <a href="host.html">Host</a> default contexts. By default, settings
diff --git a/debian/patches/CVE-2015-5346.patch b/debian/patches/CVE-2015-5346.patch
new file mode 100644
index 0000000..95f08bc
--- /dev/null
+++ b/debian/patches/CVE-2015-5346.patch
@@ -0,0 +1,142 @@
+From: Markus Koschany <apo at debian.org>
+Date: Sat, 28 May 2016 03:11:58 +0000
+Subject: CVE-2015-5346
+
+Origin: https://svn.apache.org/viewvc?view=revision&revision=1713185
+Origin: https://svn.apache.org/viewvc?view=revision&revision=1723506
+---
+ .../apache/catalina/connector/CoyoteAdapter.java | 8 ++--
+ java/org/apache/catalina/connector/Request.java | 52 ++++++++++++++--------
+ webapps/docs/changelog.xml | 8 ++++
+ 3 files changed, 46 insertions(+), 22 deletions(-)
+
+diff --git a/java/org/apache/catalina/connector/CoyoteAdapter.java b/java/org/apache/catalina/connector/CoyoteAdapter.java
+index e3ff219..775862d 100644
+--- a/java/org/apache/catalina/connector/CoyoteAdapter.java
++++ b/java/org/apache/catalina/connector/CoyoteAdapter.java
+@@ -941,9 +941,11 @@ public class CoyoteAdapter implements Adapter {
+ // Reset mapping
+ request.getMappingData().recycle();
+ mapRequired = true;
+- // Recycle cookies in case correct context is
+- // configured with different settings
+- req.getCookies().recycle();
++ // Recycle cookies and session info in case the
++ // correct context is configured with different
++ // setting
++ request.recycleSessionInfo();
++ request.recycleCookieInfo(true);
+ }
+ break;
+ }
+diff --git a/java/org/apache/catalina/connector/Request.java b/java/org/apache/catalina/connector/Request.java
+index 2d24ba4..55682be 100644
+--- a/java/org/apache/catalina/connector/Request.java
++++ b/java/org/apache/catalina/connector/Request.java
+@@ -287,6 +287,11 @@ public class Request
+ */
+ protected boolean cookiesParsed = false;
+
++ /**
++ * Cookie parsed flag. Indicates that the ServerCookies have been converted
++ * into user facing Cookie objects.
++ */
++ protected boolean cookiesConverted = false;
+
+ /**
+ * Secure flag.
+@@ -461,7 +466,6 @@ public class Request
+ parts = null;
+ }
+ partsParseException = null;
+- cookiesParsed = false;
+ locales.clear();
+ localesParsed = false;
+ secure = false;
+@@ -475,20 +479,9 @@ public class Request
+ attributes.clear();
+ sslAttributesParsed = false;
+ notes.clear();
+- cookies = null;
+
+- if (session != null) {
+- try {
+- session.endAccess();
+- } catch (Throwable t) {
+- ExceptionUtils.handleThrowable(t);
+- log.warn(sm.getString("coyoteRequest.sessionEndAccessFail"), t);
+- }
+- }
+- session = null;
+- requestedSessionCookie = false;
+- requestedSessionId = null;
+- requestedSessionURL = false;
++ recycleSessionInfo();
++ recycleCookieInfo(false);
+
+ if (Globals.IS_SECURITY_ENABLED || Connector.RECYCLE_FACADES) {
+ parameterMap = new ParameterMap<>();
+@@ -531,11 +524,32 @@ public class Request
+ }
+
+
+- /**
+- * Clear cached encoders (to save memory for Comet requests).
+- */
+- public boolean read()
+- throws IOException {
++ protected void recycleSessionInfo() {
++ if (session != null) {
++ try {
++ session.endAccess();
++ } catch (Throwable t) {
++ ExceptionUtils.handleThrowable(t);
++ log.warn(sm.getString("coyoteRequest.sessionEndAccessFail"), t);
++ }
++ }
++ session = null;
++ requestedSessionCookie = false;
++ requestedSessionId = null;
++ requestedSessionURL = false;
++ requestedSessionSSL = false;
++ }
++
++ protected void recycleCookieInfo(boolean recycleCoyote) {
++ cookiesParsed = false;
++ cookiesConverted = false;
++ cookies = null;
++ if (recycleCoyote) {
++ getCoyoteRequest().getCookies().recycle();
++ }
++ }
++
++ public boolean read() throws IOException {
+ return (inputBuffer.realReadBytes(null, 0, 0) > 0);
+ }
+
+diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
+index f552c88..cb4c914 100644
+--- a/webapps/docs/changelog.xml
++++ b/webapps/docs/changelog.xml
+@@ -184,6 +184,10 @@
+ Reduce duplicated code. All AJP connectors use common method to
+ configuration of processor. (kfujino)
+ </fix>
++ <fix>
++ <bug>58809</bug>: Correctly recycle cookies when mapping requests for
++ parallel deployment. (markt)
++ </fix>
+ </changelog>
+ </subsection>
+ <subsection name="Jasper">
+@@ -318,6 +322,10 @@
+ page that has the <code>isErrorPage</code> page directive set to
+ <code>true</code>. (markt)
+ </fix>
++ <fix>
++ Handle the unlikely case where different versions of a web application
++ are deployed with different session settings. (markt)
++ </fix>
+ </changelog>
+ </subsection>
+ <subsection name="WebSocket">
diff --git a/debian/patches/CVE-2015-5351.patch b/debian/patches/CVE-2015-5351.patch
new file mode 100644
index 0000000..88b34d0
--- /dev/null
+++ b/debian/patches/CVE-2015-5351.patch
@@ -0,0 +1,112 @@
+From: Markus Koschany <apo at debian.org>
+Date: Sat, 28 May 2016 03:13:41 +0000
+Subject: CVE-2015-5351
+
+Origin: https://svn.apache.org/viewvc?view=revision&revision=1720658
+Origin: https://svn.apache.org/viewvc?view=revision&revision=1720660
+---
+ webapps/docs/changelog.xml | 7 +++++++
+ webapps/host-manager/WEB-INF/jsp/401.jsp | 1 +
+ webapps/host-manager/WEB-INF/jsp/403.jsp | 1 +
+ webapps/host-manager/WEB-INF/jsp/404.jsp | 3 ++-
+ webapps/host-manager/index.jsp | 4 ++--
+ webapps/manager/WEB-INF/web.xml | 1 -
+ webapps/manager/index.jsp | 4 ++--
+ 7 files changed, 15 insertions(+), 6 deletions(-)
+
+diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
+index cb4c914..92d5b3c 100644
+--- a/webapps/docs/changelog.xml
++++ b/webapps/docs/changelog.xml
+@@ -326,6 +326,13 @@
+ Handle the unlikely case where different versions of a web application
+ are deployed with different session settings. (markt)
+ </fix>
++ <fix>
++ Don't create sessions unnecessarily in the Manager application. (markt)
++ </fix>
++ <fix>
++ Don't create sessions unnecessarily in the Host Manager application.
++ (markt)
++ </fix>
+ </changelog>
+ </subsection>
+ <subsection name="WebSocket">
+diff --git a/webapps/host-manager/WEB-INF/jsp/401.jsp b/webapps/host-manager/WEB-INF/jsp/401.jsp
+index 83c8c6f..047766b 100644
+--- a/webapps/host-manager/WEB-INF/jsp/401.jsp
++++ b/webapps/host-manager/WEB-INF/jsp/401.jsp
+@@ -14,6 +14,7 @@
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ --%>
++<%@ page session="false" trimDirectiveWhitespaces="true" %>
+ <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+ <html>
+ <head>
+diff --git a/webapps/host-manager/WEB-INF/jsp/403.jsp b/webapps/host-manager/WEB-INF/jsp/403.jsp
+index 2dbb448..5eff6f0 100644
+--- a/webapps/host-manager/WEB-INF/jsp/403.jsp
++++ b/webapps/host-manager/WEB-INF/jsp/403.jsp
+@@ -14,6 +14,7 @@
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ --%>
++<%@ page session="false" trimDirectiveWhitespaces="true" %>
+ <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+ <html>
+ <head>
+diff --git a/webapps/host-manager/WEB-INF/jsp/404.jsp b/webapps/host-manager/WEB-INF/jsp/404.jsp
+index d1b5b0b..9816df5 100644
+--- a/webapps/host-manager/WEB-INF/jsp/404.jsp
++++ b/webapps/host-manager/WEB-INF/jsp/404.jsp
+@@ -14,7 +14,8 @@
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ --%>
+-<%@ page import="org.apache.catalina.util.RequestUtil" %>
++<%@ page import="org.apache.catalina.util.RequestUtil" session="false"
++ trimDirectiveWhitespaces="true" %>
+ <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
+ <html>
+ <head>
+diff --git a/webapps/host-manager/index.jsp b/webapps/host-manager/index.jsp
+index d4816e5..2806b76 100644
+--- a/webapps/host-manager/index.jsp
++++ b/webapps/host-manager/index.jsp
+@@ -14,5 +14,5 @@
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ --%>
+-<% response.sendRedirect(response.encodeRedirectURL(request.getContextPath() +
+- "/html")); %>
+\ No newline at end of file
++<%@ page session="false" trimDirectiveWhitespaces="true" %>
++<% response.sendRedirect(request.getContextPath() + "/html"); %>
+\ No newline at end of file
+diff --git a/webapps/manager/WEB-INF/web.xml b/webapps/manager/WEB-INF/web.xml
+index 230199e..ef917e6 100644
+--- a/webapps/manager/WEB-INF/web.xml
++++ b/webapps/manager/WEB-INF/web.xml
+@@ -115,7 +115,6 @@
+ <filter-mapping>
+ <filter-name>CSRF</filter-name>
+ <servlet-name>HTMLManager</servlet-name>
+- <servlet-name>jsp</servlet-name>
+ </filter-mapping>
+
+ <!-- Define a Security Constraint on this Application -->
+diff --git a/webapps/manager/index.jsp b/webapps/manager/index.jsp
+index d4816e5..ff4f47b 100644
+--- a/webapps/manager/index.jsp
++++ b/webapps/manager/index.jsp
+@@ -14,5 +14,5 @@
+ See the License for the specific language governing permissions and
+ limitations under the License.
+ --%>
+-<% response.sendRedirect(response.encodeRedirectURL(request.getContextPath() +
+- "/html")); %>
+\ No newline at end of file
++<%@ page session="false" %>
++<% response.sendRedirect(request.getContextPath() + "/html"); %>
+\ No newline at end of file
diff --git a/debian/patches/CVE-2016-0706.patch b/debian/patches/CVE-2016-0706.patch
new file mode 100644
index 0000000..4f497d4
--- /dev/null
+++ b/debian/patches/CVE-2016-0706.patch
@@ -0,0 +1,34 @@
+From: Markus Koschany <apo at debian.org>
+Date: Sat, 28 May 2016 13:15:51 +0000
+Subject: CVE-2016-0706
+
+Origin: https://svn.apache.org/viewvc?view=revision&revision=1722800
+---
+ java/org/apache/catalina/core/RestrictedServlets.properties | 1 +
+ webapps/docs/changelog.xml | 4 ++++
+ 2 files changed, 5 insertions(+)
+
+diff --git a/java/org/apache/catalina/core/RestrictedServlets.properties b/java/org/apache/catalina/core/RestrictedServlets.properties
+index d336968..cefa249 100644
+--- a/java/org/apache/catalina/core/RestrictedServlets.properties
++++ b/java/org/apache/catalina/core/RestrictedServlets.properties
+@@ -16,3 +16,4 @@
+ org.apache.catalina.ssi.SSIServlet=restricted
+ org.apache.catalina.servlets.CGIServlet=restricted
+ org.apache.catalina.manager.JMXProxyServlet=restricted
++org.apache.catalina.manager.StatusManagerServlet=restricted
+diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
+index 92d5b3c..f075094 100644
+--- a/webapps/docs/changelog.xml
++++ b/webapps/docs/changelog.xml
+@@ -333,6 +333,10 @@
+ Don't create sessions unnecessarily in the Host Manager application.
+ (markt)
+ </fix>
++ <fix>
++ Add the <code>StatusManagerServlet</code> to the list of Servlets that
++ can only be loaded by privileged applications. (markt)
++ </fix>
+ </changelog>
+ </subsection>
+ <subsection name="WebSocket">
diff --git a/debian/patches/CVE-2016-0714.patch b/debian/patches/CVE-2016-0714.patch
new file mode 100644
index 0000000..cb5434c
--- /dev/null
+++ b/debian/patches/CVE-2016-0714.patch
@@ -0,0 +1,731 @@
+From: Markus Koschany <apo at debian.org>
+Date: Sun, 29 May 2016 15:11:37 +0200
+Subject: CVE-2016-0714
+
+Origin: https://svn.apache.org/viewvc?view=revision&revision=1726196
+Origin: https://svn.apache.org/viewvc?view=revision&revision=1726203
+---
+ .../catalina/ha/session/ClusterManagerBase.java | 3 +
+ .../catalina/ha/session/mbeans-descriptors.xml | 24 +++
+ .../catalina/session/LocalStrings.properties | 2 +
+ java/org/apache/catalina/session/ManagerBase.java | 172 ++++++++++++++++++++-
+ .../apache/catalina/session/StandardManager.java | 9 +-
+ .../apache/catalina/session/mbeans-descriptors.xml | 20 +++
+ .../catalina/util/CustomObjectInputStream.java | 89 ++++++++++-
+ .../apache/catalina/util/LocalStrings.properties | 2 +
+ webapps/docs/changelog.xml | 8 +
+ webapps/docs/config/cluster-manager.xml | 71 +++++++++
+ webapps/docs/config/manager.xml | 69 +++++++++
+ 11 files changed, 463 insertions(+), 6 deletions(-)
+
+diff --git a/java/org/apache/catalina/ha/session/ClusterManagerBase.java b/java/org/apache/catalina/ha/session/ClusterManagerBase.java
+index 8eb284d..ee601a8 100644
+--- a/java/org/apache/catalina/ha/session/ClusterManagerBase.java
++++ b/java/org/apache/catalina/ha/session/ClusterManagerBase.java
+@@ -196,6 +196,9 @@ public abstract class ClusterManagerBase extends ManagerBase implements ClusterM
+ copy.setProcessExpiresFrequency(getProcessExpiresFrequency());
+ copy.setNotifyListenersOnReplication(isNotifyListenersOnReplication());
+ copy.setSessionAttributeFilter(getSessionAttributeFilter());
++ copy.setSessionAttributeNameFilter(getSessionAttributeNameFilter());
++ copy.setSessionAttributeValueClassNameFilter(getSessionAttributeValueClassNameFilter());
++ copy.setWarnOnSessionAttributeFilterFailure(getWarnOnSessionAttributeFilterFailure());
+ copy.setSecureRandomClass(getSecureRandomClass());
+ copy.setSecureRandomProvider(getSecureRandomProvider());
+ copy.setSecureRandomAlgorithm(getSecureRandomAlgorithm());
+diff --git a/java/org/apache/catalina/ha/session/mbeans-descriptors.xml b/java/org/apache/catalina/ha/session/mbeans-descriptors.xml
+index 76a689e..feff5cc 100644
+--- a/java/org/apache/catalina/ha/session/mbeans-descriptors.xml
++++ b/java/org/apache/catalina/ha/session/mbeans-descriptors.xml
+@@ -309,6 +309,18 @@
+ is="true"
+ description="All session messages before state transfer message creation are dropped."
+ type="boolean"/>
++ <attribute
++ name="sessionAttributeNameFilter"
++ descritpion="The string pattern used for including session attributes in replication. Null means all attributes are included."
++ type="java.lang.String"/>
++ <attribute
++ name="sessionAttributeValueClassNameFilter"
++ description="The regular expression used to filter session attributes based on the implementation class of the value. The regular expression is anchored and must match the fully qualified class name."
++ type="java.lang.String"/>
++ <attribute
++ name="warnOnSessionAttributeFilterFailure"
++ description="Should a WARN level log message be generated if a session attribute fails to match sessionAttributeNameFilter or sessionAttributeClassNameFilter?"
++ type="boolean"/>
+ <operation
+ name="expireSession"
+ description="Expired the given session"
+@@ -530,6 +542,18 @@
+ name="secureRandomProvider"
+ description="The secure random number generator provider name"
+ type="java.lang.String"/>
++ <attribute
++ name="sessionAttributeNameFilter"
++ descritpion="The string pattern used for including session attributes in replication. Null means all attributes are included."
++ type="java.lang.String"/>
++ <attribute
++ name="sessionAttributeValueClassNameFilter"
++ description="The regular expression used to filter session attributes based on the implementation class of the value. The regular expression is anchored and must match the fully qualified class name."
++ type="java.lang.String"/>
++ <attribute
++ name="warnOnSessionAttributeFilterFailure"
++ description="Should a WARN level log message be generated if a session attribute fails to match sessionAttributeNameFilter or sessionAttributeClassNameFilter?"
++ type="boolean"/>
+ <operation
+ name="expireSession"
+ description="Expired the given session"
+diff --git a/java/org/apache/catalina/session/LocalStrings.properties b/java/org/apache/catalina/session/LocalStrings.properties
+index 7b00a4c..67eb04e 100644
+--- a/java/org/apache/catalina/session/LocalStrings.properties
++++ b/java/org/apache/catalina/session/LocalStrings.properties
+@@ -32,6 +32,8 @@ JDBCStore.missingDataSourceName=No valid JNDI name was given.
+ JDBCStore.commitSQLException=SQLException committing connection before closing
+ managerBase.container.noop=Managers added to containers other than Contexts will never be used
+ managerBase.createSession.ise=createSession: Too many active sessions
++managerBase.sessionAttributeNameFilter=Skipped session attribute named [{0}] because it did not match the name filter [{1}]
++managerBase.sessionAttributeValueClassNameFilter=Skipped session attribute named [{0}] because the value type [{1}] did not match the filter [{2}]
+ managerBase.sessionTimeout=Invalid session timeout setting {0}
+ standardManager.loading=Loading persisted sessions from {0}
+ standardManager.loading.exception=Exception while loading persisted sessions
+diff --git a/java/org/apache/catalina/session/ManagerBase.java b/java/org/apache/catalina/session/ManagerBase.java
+index b09348a..ada88f1 100644
+--- a/java/org/apache/catalina/session/ManagerBase.java
++++ b/java/org/apache/catalina/session/ManagerBase.java
+@@ -32,10 +32,13 @@ import java.util.List;
+ import java.util.Map;
+ import java.util.concurrent.ConcurrentHashMap;
+ import java.util.concurrent.atomic.AtomicLong;
++import java.util.regex.Pattern;
++import java.util.regex.PatternSyntaxException;
+
+ import org.apache.catalina.Container;
+ import org.apache.catalina.Context;
+ import org.apache.catalina.Engine;
++import org.apache.catalina.Globals;
+ import org.apache.catalina.LifecycleException;
+ import org.apache.catalina.Manager;
+ import org.apache.catalina.Session;
+@@ -210,8 +213,57 @@ public abstract class ManagerBase extends LifecycleMBeanBase
+ protected final PropertyChangeSupport support =
+ new PropertyChangeSupport(this);
+
++ private Pattern sessionAttributeNamePattern;
++ private Pattern sessionAttributeValueClassNamePattern;
++
++ private boolean warnOnSessionAttributeFilterFailure;
++
++ // ------------------------------------------------------------ Constructors
++
++ public ManagerBase() {
++ if (Globals.IS_SECURITY_ENABLED) {
++ // Minimum set required for default distribution/persistence to work
++ // plus String
++ setSessionAttributeValueClassNameFilter(
++ "java\\.lang\\.(?:Boolean|Integer|Long|Number|String)");
++ setWarnOnSessionAttributeFilterFailure(true);
++ }
++ }
++
++
++ // -------------------------------------------------------------- Properties
++
++ /**
++ * Obtain the regular expression used to filter session attribute based on
++ * attribute name. The regular expression is anchored so it must match the
++ * entire name
++ *
++ * @return The regular expression currently used to filter attribute names.
++ * {@code null} means no filter is applied. If an empty string is
++ * specified then no names will match the filter and all attributes
++ * will be blocked.
++ */
++ public String getSessionAttributeNameFilter() {
++ if (sessionAttributeNamePattern == null) {
++ return null;
++ }
++ return sessionAttributeNamePattern.toString();
++ }
++
++
++ public void setSessionAttributeNameFilter(String sessionAttributeNameFilter) {
++ if (sessionAttributeNameFilter == null || sessionAttributeNameFilter.length() == 0) {
++ sessionAttributeNamePattern = null;
++ }
++ sessionAttributeNamePattern = Pattern.compile(sessionAttributeNameFilter);
++ }
++
++
++ protected Pattern getSessionAttributeNamePattern() {
++ return sessionAttributeNamePattern;
++ }
++
+
+- // ------------------------------------------------------------- Properties
+
+ @Override
+ @Deprecated
+@@ -220,6 +272,86 @@ public abstract class ManagerBase extends LifecycleMBeanBase
+ }
+
+
++ /**
++ * Obtain the regular expression used to filter session attribute based on
++ * the implementation class of the value. The regular expression is anchored
++ * and must match the fully qualified class name.
++ *
++ * @return The regular expression currently used to filter class names.
++ * {@code null} means no filter is applied. If an empty string is
++ * specified then no names will match the filter and all attributes
++ * will be blocked.
++ */
++ public String getSessionAttributeValueClassNameFilter() {
++ if (sessionAttributeValueClassNamePattern == null) {
++ return null;
++ }
++ return sessionAttributeValueClassNamePattern.toString();
++ }
++
++
++ /**
++ * Provides {@link #getSessionAttributeValueClassNameFilter()} as a
++ * pre-compiled regular expression pattern.
++ *
++ * @return The pre-compiled pattern used to filter session attributes based
++ * on the implementation class name of the value. {@code null} means
++ * no filter is applied.
++ */
++ protected Pattern getSessionAttributeValueClassNamePattern() {
++ return sessionAttributeValueClassNamePattern;
++ }
++
++
++ /**
++ * Set the regular expression to use to filter classes used for session
++ * attributes. The regular expression is anchored and must match the fully
++ * qualified class name.
++ *
++ * @param sessionAttributeValueClassNameFilter The regular expression to use
++ * to filter session attributes based on class name. Use {@code
++ * null} if no filtering is required. If an empty string is
++ * specified then no names will match the filter and all
++ * attributes will be blocked.
++ *
++ * @throws PatternSyntaxException If the expression is not valid
++ */
++ public void setSessionAttributeValueClassNameFilter(String sessionAttributeValueClassNameFilter)
++ throws PatternSyntaxException {
++ if (sessionAttributeValueClassNameFilter == null ||
++ sessionAttributeValueClassNameFilter.length() == 0) {
++ sessionAttributeValueClassNamePattern = null;
++ }
++ sessionAttributeValueClassNamePattern =
++ Pattern.compile(sessionAttributeValueClassNameFilter);
++ }
++
++
++ /**
++ * Should a warn level log message be generated if a session attribute is
++ * not persisted / replicated / restored.
++ *
++ * @return {@code true} if a warn level log message should be generated
++ */
++ public boolean getWarnOnSessionAttributeFilterFailure() {
++ return warnOnSessionAttributeFilterFailure;
++ }
++
++
++ /**
++ * Configure whether or not a warn level log message should be generated if
++ * a session attribute is not persisted / replicated / restored.
++ *
++ * @param warnOnSessionAttributeFilterFailure {@code true} if the
++ * warn level message should be generated
++ *
++ */
++ public void setWarnOnSessionAttributeFilterFailure(
++ boolean warnOnSessionAttributeFilterFailure) {
++ this.warnOnSessionAttributeFilterFailure = warnOnSessionAttributeFilterFailure;
++ }
++
++
+ @Override
+ @Deprecated
+ public void setContainer(Container container) {
+@@ -839,6 +971,44 @@ public abstract class ManagerBase extends LifecycleMBeanBase
+ notifySessionListeners, notifyContainerListeners);
+ }
+
++ public boolean willAttributeDistribute(String name, Object value) {
++ Pattern sessionAttributeNamePattern = getSessionAttributeNamePattern();
++ if (sessionAttributeNamePattern != null) {
++ if (!sessionAttributeNamePattern.matcher(name).matches()) {
++ if (getWarnOnSessionAttributeFilterFailure() || log.isDebugEnabled()) {
++ String msg = sm.getString("managerBase.sessionAttributeNameFilter",
++ name, sessionAttributeNamePattern);
++ if (getWarnOnSessionAttributeFilterFailure()) {
++ log.warn(msg);
++ } else {
++ log.debug(msg);
++ }
++ }
++ return false;
++ }
++ }
++
++
++ Pattern sessionAttributeValueClassNamePattern = getSessionAttributeValueClassNamePattern();
++ if (value != null && sessionAttributeValueClassNamePattern != null) {
++ if (!sessionAttributeValueClassNamePattern.matcher(
++ value.getClass().getName()).matches()) {
++ if (getWarnOnSessionAttributeFilterFailure() || log.isDebugEnabled()) {
++ String msg = sm.getString("managerBase.sessionAttributeValueClassNameFilter",
++ name, value.getClass().getName(), sessionAttributeNamePattern);
++ if (getWarnOnSessionAttributeFilterFailure()) {
++ log.warn(msg);
++ } else {
++ log.debug(msg);
++ }
++ }
++ return false;
++ }
++ }
++
++ return true;
++
++ }
+
+ // ------------------------------------------------------ Protected Methods
+
+diff --git a/java/org/apache/catalina/session/StandardManager.java b/java/org/apache/catalina/session/StandardManager.java
+index b1eb80b..a63ae7e 100644
+--- a/java/org/apache/catalina/session/StandardManager.java
++++ b/java/org/apache/catalina/session/StandardManager.java
+@@ -208,19 +208,24 @@ public class StandardManager extends ManagerBase {
+ BufferedInputStream bis = null;
+ ObjectInputStream ois = null;
+ Loader loader = null;
++ Log logger = null;
+ ClassLoader classLoader = null;
+ try {
+ fis = new FileInputStream(file.getAbsolutePath());
+ bis = new BufferedInputStream(fis);
+ Context c = getContext();
+- if (c != null)
++ if (c != null) {
+ loader = c.getLoader();
++ logger = c.getLogger();
++ }
+ if (loader != null)
+ classLoader = loader.getClassLoader();
+ if (classLoader != null) {
+ if (log.isDebugEnabled())
+ log.debug("Creating custom object input stream for class loader ");
+- ois = new CustomObjectInputStream(bis, classLoader);
++ ois = new CustomObjectInputStream(bis, classLoader, logger,
++ getSessionAttributeValueClassNamePattern(),
++ getWarnOnSessionAttributeFilterFailure());
+ } else {
+ if (log.isDebugEnabled())
+ log.debug("Creating standard object input stream");
+diff --git a/java/org/apache/catalina/session/mbeans-descriptors.xml b/java/org/apache/catalina/session/mbeans-descriptors.xml
+index 4f9b01e..4edf79b 100644
+--- a/java/org/apache/catalina/session/mbeans-descriptors.xml
++++ b/java/org/apache/catalina/session/mbeans-descriptors.xml
+@@ -132,6 +132,15 @@
+ description="Number of sessions we rejected due to maxActive beeing reached"
+ type="int"
+ writeable="false"/>
++ <attribute name="sessionAttributeNameFilter" description="The string pattern used for including session attributes in distribution. Null means all attributes are included."
++ type="java.lang.String"/>
++ <attribute name="sessionAttributeValueClassNameFilter"
++ description="The regular expression used to filter session attributes based on the implementation class of the value. The regular expression is anchored and must match the fully qualified class name."
++ type="java.lang.String"/>
++
++ <attribute name="warnOnSessionAttributeFilterFailure"
++ description="Should a WARN level log message be generated if a session attribute fails to match sessionAttributeNameFilter or sessionAttributeClassNameFilter?"
++ type="boolean"/>
+
+ <operation name="backgroundProcess"
+ description="Invalidate all sessions that have expired."
+@@ -321,6 +330,17 @@
+ type="int"
+ writeable="false"/>
+
++ <attribute name="sessionAttributeNameFilter" description="The string pattern used for including session attributes in distribution. Null means all attributes are included."
++ type="java.lang.String"/>
++
++ <attribute name="sessionAttributeValueClassNameFilter"
++ description="The regular expression used to filter session attributes based on the implementation class of the value. The regular expression is anchored and must match the fully qualified class name."
++ type="java.lang.String"/>
++
++ <attribute name="warnOnSessionAttributeFilterFailure"
++ description="Should a WARN level log message be generated if a session attribute fails to match sessionAttributeNameFilter or sessionAttributeClassNameFilter?"
++ type="boolean"/>
++
+ <operation name="backgroundProcess"
+ description="Invalidate all sessions that have expired."
+ impact="ACTION"
+diff --git a/java/org/apache/catalina/util/CustomObjectInputStream.java b/java/org/apache/catalina/util/CustomObjectInputStream.java
+index f63d777..25793e4 100644
+--- a/java/org/apache/catalina/util/CustomObjectInputStream.java
++++ b/java/org/apache/catalina/util/CustomObjectInputStream.java
+@@ -19,9 +19,18 @@ package org.apache.catalina.util;
+
+ import java.io.IOException;
+ import java.io.InputStream;
++import java.io.InvalidClassException;
+ import java.io.ObjectInputStream;
+ import java.io.ObjectStreamClass;
+ import java.lang.reflect.Proxy;
++import java.util.Collections;
++import java.util.Set;
++import java.util.WeakHashMap;
++import java.util.concurrent.ConcurrentHashMap;
++import java.util.regex.Pattern;
++
++import org.apache.juli.logging.Log;
++import org.apache.tomcat.util.res.StringManager;
+
+ /**
+ * Custom subclass of <code>ObjectInputStream</code> that loads from the
+@@ -35,14 +44,26 @@ public final class CustomObjectInputStream
+ extends ObjectInputStream {
+
+
++ private static final StringManager sm = StringManager.getManager("org.apache.catalina.util");
++
++ private static final WeakHashMap<ClassLoader, Set<String>> reportedClassCache =
++ new WeakHashMap<>();
++
+ /**
+ * The class loader we will use to resolve classes.
+ */
+ private final ClassLoader classLoader;
++ private final Set<String> reportedClasses;
++ private final Log log;
++
++ private final Pattern allowedClassNamePattern;
++ private final String allowedClassNameFilter;
++ private final boolean warnOnFailure;
+
+
+ /**
+- * Construct a new instance of CustomObjectInputStream
++ * Construct a new instance of CustomObjectInputStream without any filtering
++ * of deserialized classes.
+ *
+ * @param stream The input stream we will read from
+ * @param classLoader The class loader used to instantiate objects
+@@ -53,10 +74,56 @@ public final class CustomObjectInputStream
+ ClassLoader classLoader)
+ throws IOException {
+
++ this(stream, classLoader, null, null, false);
++ }
++
++
++
++ /**
++ * Construct a new instance of CustomObjectInputStream with filtering of
++ * deserialized classes.
++ *
++ * @param stream The input stream we will read from
++ * @param classLoader The class loader used to instantiate objects
++ * @param log The logger to use to report any issues. It may only be null if
++ * the filterMode does not require logging
++ * @param allowedClassNamePattern The regular expression to use to filter
++ * deserialized classes. The fully qualified
++ * class name must match this pattern for
++ * deserialization to be allowed if filtering
++ * is enabled.
++ * @param warnOnFailure Should any failures be logged?
++ *
++ * @exception IOException if an input/output error occurs
++ */
++ public CustomObjectInputStream(InputStream stream, ClassLoader classLoader,
++ Log log, Pattern allowedClassNamePattern, boolean warnOnFailure)
++ throws IOException {
+ super(stream);
++ if (log == null && allowedClassNamePattern != null && warnOnFailure) {
++ throw new IllegalArgumentException(
++ sm.getString("customObjectInputStream.logRequired"));
++ }
+ this.classLoader = classLoader;
+- }
++ this.log = log;
++ this.allowedClassNamePattern = allowedClassNamePattern;
++ if (allowedClassNamePattern == null) {
++ this.allowedClassNameFilter = null;
++ } else {
++ this.allowedClassNameFilter = allowedClassNamePattern.toString();
++ }
++ this.warnOnFailure = warnOnFailure;
+
++ Set<String> reportedClasses;
++ synchronized (reportedClassCache) {
++ reportedClasses = reportedClassCache.get(classLoader);
++ if (reportedClasses == null) {
++ reportedClasses = Collections.newSetFromMap(new ConcurrentHashMap<String,Boolean>());
++ reportedClassCache.put(classLoader, reportedClasses);
++ }
++ }
++ this.reportedClasses = reportedClasses;
++ }
+
+ /**
+ * Load the local class equivalent of the specified stream class
+@@ -70,8 +137,24 @@ public final class CustomObjectInputStream
+ @Override
+ public Class<?> resolveClass(ObjectStreamClass classDesc)
+ throws ClassNotFoundException, IOException {
++
++ String name = classDesc.getName();
++ if (allowedClassNamePattern != null) {
++ boolean allowed = allowedClassNamePattern.matcher(name).matches();
++ if (!allowed) {
++ boolean doLog = warnOnFailure && reportedClasses.add(name);
++ String msg = sm.getString("customObjectInputStream.nomatch", name, allowedClassNameFilter);
++ if (doLog) {
++ log.warn(msg);
++ } else if (log.isDebugEnabled()) {
++ log.debug(msg);
++ }
++ throw new InvalidClassException(msg);
++ }
++ }
++
+ try {
+- return Class.forName(classDesc.getName(), false, classLoader);
++ return Class.forName(name, false, classLoader);
+ } catch (ClassNotFoundException e) {
+ try {
+ // Try also the superclass because of primitive types
+diff --git a/java/org/apache/catalina/util/LocalStrings.properties b/java/org/apache/catalina/util/LocalStrings.properties
+index 55dea98..6aeb973 100644
+--- a/java/org/apache/catalina/util/LocalStrings.properties
++++ b/java/org/apache/catalina/util/LocalStrings.properties
+@@ -17,6 +17,8 @@ parameterMap.locked=No modifications are allowed to a locked ParameterMap
+ resourceSet.locked=No modifications are allowed to a locked ResourceSet
+ hexUtil.bad=Bad hexadecimal digit
+ hexUtil.odd=Odd number of hexadecimal digits
++customObjectInputStream.logRequired=A valid logger is required for class name filtering with logging
++customObjectInputStream.nomatch=The class [{0}] did not match the regular expression [{1}] for classes allowed to be deserialized
+ #Default Messages Utilized by the ExtensionValidator
+ extensionValidator.web-application-manifest=Web Application Manifest
+ extensionValidator.extension-not-found-error=ExtensionValidator[{0}][{1}]: Required extension [{2}] not found.
+diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
+index d18692c..a0b4788 100644
+--- a/webapps/docs/changelog.xml
++++ b/webapps/docs/changelog.xml
+@@ -308,6 +308,14 @@
+ Add support for the EECDH alias when using the OpenSSL cipher syntax to
+ define JSSE ciphers. (markt)
+ </add>
++ <add>
++ Extend the session attribute filtering options to include filtering
++ based on the implementation class of the value and optional
++ <code>WARN</code> level logging if an attribute is filtered. These
++ options are avaialble for all of the Manager implementations that ship
++ with Tomcat. When a <code>SecurityManager</code> is used filtering will
++ be enabled by default. (markt)
++ </add>
+ </changelog>
+ </subsection>
+ <subsection name="Jasper">
+diff --git a/webapps/docs/config/cluster-manager.xml b/webapps/docs/config/cluster-manager.xml
+index 377884a..4958a39 100644
+--- a/webapps/docs/config/cluster-manager.xml
++++ b/webapps/docs/config/cluster-manager.xml
+@@ -97,6 +97,7 @@
+ varied by a servlet via the
+ <code>setMaxInactiveInterval</code> method of the <code>HttpSession</code> object.</p>
+ </attribute>
++
+ <attribute name="sessionIdLength" required="false">
+ <p>The length of session ids created by this Manager, measured in bytes,
+ excluding subsequent conversion to a hexadecimal string and
+@@ -182,6 +183,30 @@
+ effective only when <code>sendAllSessions</code> is <code>false</code>.
+ Default is <code>2000</code> milliseconds.
+ </attribute>
++
++ <attribute name="sessionAttributeNameFilter" required="false">
++ <p>A regular expression used to filter which session attributes will be
++ replicated. An attribute will only be replicated if its name matches
++ this pattern. If the pattern is zero length or <code>null</code>, all
++ attributes are eligible for replication. The pattern is anchored so the
++ session attribute name must fully match the pattern. As an example, the
++ value <code>(userName|sessionHistory)</code> will only replicate the
++ two session attributes named <code>userName</code> and
++ <code>sessionHistory</code>. If not specified, the default value of
++ <code>null</code> will be used.</p>
++ </attribute>
++ <attribute name="sessionAttributeValueClassNameFilter" required="false">
++ <p>A regular expression used to filter which session attributes will be
++ replicated. An attribute will only be replicated if the implementation
++ class name of the value matches this pattern. If the pattern is zero
++ length or <code>null</code>, all attributes are eligible for
++ replication. The pattern is anchored so the fully qualified class name
++ must fully match the pattern. If not specified, the default value of
++ <code>null</code> will be used unless a <code>SecurityManager</code> is
++ enabled in which case the default will be
++ <code>java\\.lang\\.(?:Boolean|Integer|Long|Number|String)</code>.</p>
++ </attribute>
++
+ <attribute name="stateTimestampDrop" required="false">
+ When this node sends a <code>GET_ALL_SESSIONS</code> message to other
+ node, all session messages that are received as a response are queued.
+@@ -193,6 +218,17 @@
+ If set to <code>false</code>, all queued session messages are handled.
+ Default is <code>true</code>.
+ </attribute>
++
++ <attribute name="warnOnSessionAttributeFilterFailure" required="false">
++ <p>If <strong>sessionAttributeNameFilter</strong> or
++ <strong>sessionAttributeValueClassNameFilter</strong> blocks an
++ attribute, should this be logged at <code>WARN</code> level? If
++ <code>WARN</code> level logging is disabled then it will be logged at
++ <code>DEBUG</code>. The default value of this attribute is
++ <code>false</code> unless a <code>SecurityManager</code> is enabled in
++ which case the default will be <code>true</code>.</p>
++ </attribute>
++
+ </attributes>
+ </subsection>
+ <subsection name="org.apache.catalina.ha.session.BackupManager Attributes">
+@@ -216,6 +252,30 @@
+ another map.
+ Default value is <code>15000</code> milliseconds.
+ </attribute>
++
++ <attribute name="sessionAttributeNameFilter" required="false">
++ <p>A regular expression used to filter which session attributes will be
++ replicated. An attribute will only be replicated if its name matches
++ this pattern. If the pattern is zero length or <code>null</code>, all
++ attributes are eligible for replication. The pattern is anchored so the
++ session attribute name must fully match the pattern. As an example, the
++ value <code>(userName|sessionHistory)</code> will only replicate the
++ two session attributes named <code>userName</code> and
++ <code>sessionHistory</code>. If not specified, the default value of
++ <code>null</code> will be used.</p>
++ </attribute>
++ <attribute name="sessionAttributeValueClassNameFilter" required="false">
++ <p>A regular expression used to filter which session attributes will be
++ replicated. An attribute will only be replicated if the implementation
++ class name of the value matches this pattern. If the pattern is zero
++ length or <code>null</code>, all attributes are eligible for
++ replication. The pattern is anchored so the fully qualified class name
++ must fully match the pattern. If not specified, the default value of
++ <code>null</code> will be used unless a <code>SecurityManager</code> is
++ enabled in which case the default will be
++ <code>java\\.lang\\.(?:Boolean|Integer|Long|Number|String)</code>.</p>
++ </attribute>
++
+ <attribute name="terminateOnStartFailure" required="false">
+ Set to true if you wish to terminate replication map when replication
+ map fails to start. If replication map is terminated, associated context
+@@ -223,6 +283,17 @@
+ does not end. It will try to join the map membership in the heartbeat.
+ Default value is <code>false</code> .
+ </attribute>
++
++ <attribute name="warnOnSessionAttributeFilterFailure" required="false">
++ <p>If <strong>sessionAttributeNameFilter</strong> or
++ <strong>sessionAttributeValueClassNameFilter</strong> blocks an
++ attribute, should this be logged at <code>WARN</code> level? If
++ <code>WARN</code> level logging is disabled then it will be logged at
++ <code>DEBUG</code>. The default value of this attribute is
++ <code>false</code> unless a <code>SecurityManager</code> is enabled in
++ which case the default will be <code>true</code>.</p>
++ </attribute>
++
+ </attributes>
+ </subsection>
+ </section>
+diff --git a/webapps/docs/config/manager.xml b/webapps/docs/config/manager.xml
+index 3ab728b..3726fe5 100644
+--- a/webapps/docs/config/manager.xml
++++ b/webapps/docs/config/manager.xml
+@@ -175,6 +175,40 @@
+ string.</p>
+ </attribute>
+
++ <attribute name="sessionAttributeNameFilter" required="false">
++ <p>A regular expression used to filter which session attributes will be
++ distributed. An attribute will only be distributed if its name matches
++ this pattern. If the pattern is zero length or <code>null</code>, all
++ attributes are eligible for distribution. The pattern is anchored so the
++ session attribute name must fully match the pattern. As an example, the
++ value <code>(userName|sessionHistory)</code> will only distribute the
++ two session attributes named <code>userName</code> and
++ <code>sessionHistory</code>. If not specified, the default value of
++ <code>null</code> will be used.</p>
++ </attribute>
++
++ <attribute name="sessionAttributeValueClassNameFilter" required="false">
++ <p>A regular expression used to filter which session attributes will be
++ distributed. An attribute will only be distributed if the implementation
++ class name of the value matches this pattern. If the pattern is zero
++ length or <code>null</code>, all attributes are eligible for
++ distribution. The pattern is anchored so the fully qualified class name
++ must fully match the pattern. If not specified, the default value of
++ <code>null</code> will be used unless a <code>SecurityManager</code> is
++ enabled in which case the default will be
++ <code>java\\.lang\\.(?:Boolean|Integer|Long|Number|String)</code>.</p>
++ </attribute>
++
++ <attribute name="warnOnSessionAttributeFilterFailure" required="false">
++ <p>If <strong>sessionAttributeNameFilter</strong> or
++ <strong>sessionAttributeValueClassNameFilter</strong> blocks an
++ attribute, should this be logged at <code>WARN</code> level? If
++ <code>WARN</code> level logging is disabled then it will be logged at
++ <code>DEBUG</code>. The default value of this attribute is
++ <code>false</code> unless a <code>SecurityManager</code> is enabled in
++ which case the default will be <code>true</code>.</p>
++ </attribute>
++
+ </attributes>
+
+ <h3>Persistent Manager Implementation</h3>
+@@ -264,6 +298,41 @@
+ <code>org.apache.catalina.session.StandardManager</code> class.
+ </p>
+ </attribute>
++
++ <attribute name="sessionAttributeNameFilter" required="false">
++ <p>A regular expression used to filter which session attributes will be
++ distributed. An attribute will only be distributed if its name matches
++ this pattern. If the pattern is zero length or <code>null</code>, all
++ attributes are eligible for distribution. The pattern is anchored so the
++ session attribute name must fully match the pattern. As an example, the
++ value <code>(userName|sessionHistory)</code> will only distribute the
++ two session attributes named <code>userName</code> and
++ <code>sessionHistory</code>. If not specified, the default value of
++ <code>null</code> will be used.</p>
++ </attribute>
++
++ <attribute name="sessionAttributeValueClassNameFilter" required="false">
++ <p>A regular expression used to filter which session attributes will be
++ distributed. An attribute will only be distributed if the implementation
++ class name of the value matches this pattern. If the pattern is zero
++ length or <code>null</code>, all attributes are eligible for
++ distribution. The pattern is anchored so the fully qualified class name
++ must fully match the pattern. If not specified, the default value of
++ <code>null</code> will be used unless a <code>SecurityManager</code> is
++ enabled in which case the default will be
++ <code>java\\.lang\\.(?:Boolean|Integer|Long|Number|String)</code>.</p>
++ </attribute>
++
++ <attribute name="warnOnSessionAttributeFilterFailure" required="false">
++ <p>If <strong>sessionAttributeNameFilter</strong> or
++ <strong>sessionAttributeValueClassNameFilter</strong> blocks an
++ attribute, should this be logged at <code>WARN</code> level? If
++ <code>WARN</code> level logging is disabled then it will be logged at
++ <code>DEBUG</code>. The default value of this attribute is
++ <code>false</code> unless a <code>SecurityManager</code> is enabled in
++ which case the default will be <code>true</code>.</p>
++ </attribute>
++
+ </attributes>
+
+ <p>In order to successfully use a PersistentManager, you must nest inside
diff --git a/debian/patches/CVE-2016-0763.patch b/debian/patches/CVE-2016-0763.patch
new file mode 100644
index 0000000..1e8e34e
--- /dev/null
+++ b/debian/patches/CVE-2016-0763.patch
@@ -0,0 +1,41 @@
+From: Markus Koschany <apo at debian.org>
+Date: Sat, 28 May 2016 15:46:37 +0200
+Subject: CVE-2016-0763
+
+Origin: https://svn.apache.org/viewvc?view=revision&revision=1725929
+---
+ java/org/apache/naming/factory/ResourceLinkFactory.java | 5 +++++
+ webapps/docs/changelog.xml | 4 ++++
+ 2 files changed, 9 insertions(+)
+
+diff --git a/java/org/apache/naming/factory/ResourceLinkFactory.java b/java/org/apache/naming/factory/ResourceLinkFactory.java
+index 808192c..8a43e74 100644
+--- a/java/org/apache/naming/factory/ResourceLinkFactory.java
++++ b/java/org/apache/naming/factory/ResourceLinkFactory.java
+@@ -60,6 +60,11 @@ public class ResourceLinkFactory
+ * @param newGlobalContext new global context value
+ */
+ public static void setGlobalContext(Context newGlobalContext) {
++ SecurityManager sm = System.getSecurityManager();
++ if (sm != null) {
++ sm.checkPermission(new RuntimePermission(
++ ResourceLinkFactory.class.getName() + ".setGlobalContext"));
++ }
+ globalContext = newGlobalContext;
+ }
+
+diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
+index f075094..d18692c 100644
+--- a/webapps/docs/changelog.xml
++++ b/webapps/docs/changelog.xml
+@@ -337,6 +337,10 @@
+ Add the <code>StatusManagerServlet</code> to the list of Servlets that
+ can only be loaded by privileged applications. (markt)
+ </fix>
++ <fix>
++ Protect initialization of <code>ResourceLinkFactory</code> when
++ running with a SecurityManager. (kkolinko)
++ </fix>
+ </changelog>
+ </subsection>
+ <subsection name="WebSocket">
diff --git a/debian/patches/series b/debian/patches/series
index 86954a1..3b86510 100644
--- a/debian/patches/series
+++ b/debian/patches/series
@@ -13,3 +13,10 @@
0019-add-distribution-to-error-page.patch
#0020-disable-java8-support-with-jdtcompiler.patch
CVE-2014-7810.patch
+CVE-2015-5174.patch
+CVE-2015-5346.patch
+CVE-2015-5351.patch
+CVE-2016-0706.patch
+CVE-2016-0763.patch
+CVE-2016-0714.patch
+CVE-2015-5345.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