diff --git a/CVE-2023-28708-pre.patch b/CVE-2023-28708-pre.patch new file mode 100644 index 0000000..01ed17b --- /dev/null +++ b/CVE-2023-28708-pre.patch @@ -0,0 +1,238 @@ +From 09e214c09c78a48ea96b0137555b3c2a98a1bfab Mon Sep 17 00:00:00 2001 +From: Mark Thomas +Date: Tue, 31 Mar 2020 14:03:17 +0100 +Subject: [PATCH] Make the HTTP/2 connection ID and stream Id available to + applications +Origin: https://github.com/apache/tomcat/commit/09e214c09c78a48ea96b0137555b3c2a98a1bfab + +--- + java/org/apache/catalina/Globals.java | 16 ++++++++ + .../apache/catalina/connector/Request.java | 27 +++++++++++++ + java/org/apache/coyote/AbstractProcessor.java | 39 +++++++++++++++++++ + java/org/apache/coyote/ActionCode.java | 14 ++++++- + .../apache/coyote/http2/StreamProcessor.java | 12 ++++++ + webapps/docs/changelog.xml | 5 +++ + webapps/docs/config/http2.xml | 9 +++++ + 7 files changed, 121 insertions(+), 1 deletion(-) + +diff --git a/java/org/apache/catalina/Globals.java b/java/org/apache/catalina/Globals.java +index 994902b..c19d69c 100644 +--- a/java/org/apache/catalina/Globals.java ++++ b/java/org/apache/catalina/Globals.java +@@ -112,6 +112,22 @@ public final class Globals { + "org.apache.catalina.NAMED"; + + ++ /** ++ * The request attribute used to expose the current connection ID associated ++ * with the request, if any. Used with multiplexing protocols such as ++ * HTTTP/2. ++ */ ++ public static final String CONNECTION_ID = "org.apache.coyote.connectionID"; ++ ++ ++ /** ++ * The request attribute used to expose the current stream ID associated ++ * with the request, if any. Used with multiplexing protocols such as ++ * HTTTP/2. ++ */ ++ public static final String STREAM_ID = "org.apache.coyote.streamID"; ++ ++ + /** + * The servlet context attribute under which we store a flag used + * to mark this request as having been processed by the SSIServlet. +diff --git a/java/org/apache/catalina/connector/Request.java b/java/org/apache/catalina/connector/Request.java +index c4cc26a..94065ef 100644 +--- a/java/org/apache/catalina/connector/Request.java ++++ b/java/org/apache/catalina/connector/Request.java +@@ -40,6 +40,7 @@ import java.util.TimeZone; + import java.util.TreeMap; + import java.util.concurrent.ConcurrentHashMap; + import java.util.concurrent.atomic.AtomicBoolean; ++import java.util.concurrent.atomic.AtomicReference; + + import javax.naming.NamingException; + import javax.security.auth.Subject; +@@ -3487,6 +3488,32 @@ public class Request implements HttpServletRequest { + // NO-OP + } + }); ++ specialAttributes.put(Globals.CONNECTION_ID, ++ new SpecialAttributeAdapter() { ++ @Override ++ public Object get(Request request, String name) { ++ AtomicReference result = new AtomicReference<>(); ++ request.getCoyoteRequest().action(ActionCode.CONNECTION_ID, result); ++ return result.get(); ++ } ++ @Override ++ public void set(Request request, String name, Object value) { ++ // NO-OP ++ } ++ }); ++ specialAttributes.put(Globals.STREAM_ID, ++ new SpecialAttributeAdapter() { ++ @Override ++ public Object get(Request request, String name) { ++ AtomicReference result = new AtomicReference<>(); ++ request.getCoyoteRequest().action(ActionCode.STREAM_ID, result); ++ return result.get(); ++ } ++ @Override ++ public void set(Request request, String name, Object value) { ++ // NO-OP ++ } ++ }); + + for (SimpleDateFormat sdf : formatsTemplate) { + sdf.setTimeZone(GMT_ZONE); +diff --git a/java/org/apache/coyote/AbstractProcessor.java b/java/org/apache/coyote/AbstractProcessor.java +index 5be2cb8..b351cb7 100644 +--- a/java/org/apache/coyote/AbstractProcessor.java ++++ b/java/org/apache/coyote/AbstractProcessor.java +@@ -22,6 +22,7 @@ import java.nio.ByteBuffer; + import java.util.Iterator; + import java.util.concurrent.RejectedExecutionException; + import java.util.concurrent.atomic.AtomicBoolean; ++import java.util.concurrent.atomic.AtomicReference; + + import javax.servlet.RequestDispatcher; + +@@ -589,6 +590,20 @@ public abstract class AbstractProcessor extends AbstractProcessorLight implement + result.set(isTrailerFieldsSupported()); + break; + } ++ ++ // Identifiers associated with multiplexing protocols like HTTP/2 ++ case CONNECTION_ID: { ++ @SuppressWarnings("unchecked") ++ AtomicReference result = (AtomicReference) param; ++ result.set(getConnectionID()); ++ break; ++ } ++ case STREAM_ID: { ++ @SuppressWarnings("unchecked") ++ AtomicReference result = (AtomicReference) param; ++ result.set(getStreamID()); ++ break; ++ } + } + } + +@@ -889,6 +904,30 @@ public abstract class AbstractProcessor extends AbstractProcessorLight implement + } + + ++ /** ++ * Protocols that support multiplexing (e.g. HTTP/2) should override this ++ * method and return the appropriate ID. ++ * ++ * @return The stream ID associated with this request or {@code null} if a ++ * multiplexing protocol is not being used ++ */ ++ protected Object getConnectionID() { ++ return null; ++ } ++ ++ ++ /** ++ * Protocols that support multiplexing (e.g. HTTP/2) should override this ++ * method and return the appropriate ID. ++ * ++ * @return The stream ID associated with this request or {@code null} if a ++ * multiplexing protocol is not being used ++ */ ++ protected Object getStreamID() { ++ return null; ++ } ++ ++ + /** + * Flush any pending writes. Used during non-blocking writes to flush any + * remaining data from a previous incomplete write. +diff --git a/java/org/apache/coyote/ActionCode.java b/java/org/apache/coyote/ActionCode.java +index 3ff4c21..5c5af4f 100644 +--- a/java/org/apache/coyote/ActionCode.java ++++ b/java/org/apache/coyote/ActionCode.java +@@ -265,5 +265,17 @@ public enum ActionCode { + * once an HTTP/1.1 response has been committed, it will no longer support + * trailer fields. + */ +- IS_TRAILER_FIELDS_SUPPORTED ++ IS_TRAILER_FIELDS_SUPPORTED, ++ ++ /** ++ * Obtain the connection identifier for the request. Used with multiplexing ++ * protocols such as HTTP/2. ++ */ ++ CONNECTION_ID, ++ ++ /** ++ * Obtain the stream identifier for the request. Used with multiplexing ++ * protocols such as HTTP/2. ++ */ ++ STREAM_ID + } +diff --git a/java/org/apache/coyote/http2/StreamProcessor.java b/java/org/apache/coyote/http2/StreamProcessor.java +index d9c1c82..fd833ec 100644 +--- a/java/org/apache/coyote/http2/StreamProcessor.java ++++ b/java/org/apache/coyote/http2/StreamProcessor.java +@@ -300,6 +300,18 @@ class StreamProcessor extends AbstractProcessor { + } + + ++ @Override ++ protected Object getConnectionID() { ++ return stream.getConnectionId(); ++ } ++ ++ ++ @Override ++ protected Object getStreamID() { ++ return stream.getIdentifier().toString(); ++ } ++ ++ + @Override + public final void recycle() { + // StreamProcessor instances are not re-used. +diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml +index a97e15d..8837628 100644 +--- a/webapps/docs/changelog.xml ++++ b/webapps/docs/changelog.xml +@@ -247,6 +247,11 @@ + Ensure that the HTTP/1.1 processor is correctly recycled when a direct + connection to h2c is made. (markt) + ++ ++ Expose the HTTP/2 connection ID and stream ID to applications via the ++ request attributes org.apache.coyote.connectionID and ++ org.apache.coyote.streamID respectively. (markt) ++ + + + +diff --git a/webapps/docs/config/http2.xml b/webapps/docs/config/http2.xml +index 83b8acd..145a184 100644 +--- a/webapps/docs/config/http2.xml ++++ b/webapps/docs/config/http2.xml +@@ -44,6 +44,15 @@ + the Servlet API is fundamentally blocking, each HTTP/2 stream requires a + dedicated container thread for the duration of that stream.

+ ++

Requests processed using HTTP/2 will have the following additional request ++ attributes available:

++
    ++
  • org.apache.coyote.connectionID will return the HTTP/2 ++ connection ID
  • ++
  • org.apache.coyote.streamID will return the HTTP/2 stream ++ ID
  • ++
++ + + + +-- +2.33.0 + diff --git a/CVE-2023-28708.patch b/CVE-2023-28708.patch new file mode 100644 index 0000000..1d03fc7 --- /dev/null +++ b/CVE-2023-28708.patch @@ -0,0 +1,232 @@ +From 3b51230764da595bb19e8d0962dd8c69ab40dfab Mon Sep 17 00:00:00 2001 +From: lihan +Date: Fri, 10 Feb 2023 10:01:27 +0800 +Subject: [PATCH] Fix BZ 66471 - JSessionId secure attribute missing with + RemoteIpFilter and X-Forwarded-Proto set to https + +https://bz.apache.org/bugzilla/show_bug.cgi?id=66471 + +Origin: https://github.com/apache/tomcat/commit/3b51230764da595bb19e8d0962dd8c69ab40dfab +--- + java/org/apache/catalina/Globals.java | 8 ++ + .../apache/catalina/connector/Request.java | 14 +++ + .../catalina/filters/RemoteIpFilter.java | 7 +- + .../catalina/filters/TestRemoteIpFilter.java | 96 ++++++++++++++----- + webapps/docs/changelog.xml | 5 + + 5 files changed, 101 insertions(+), 29 deletions(-) + +diff --git a/java/org/apache/catalina/Globals.java b/java/org/apache/catalina/Globals.java +index c19d69c..2e9a377 100644 +--- a/java/org/apache/catalina/Globals.java ++++ b/java/org/apache/catalina/Globals.java +@@ -160,6 +160,14 @@ public final class Globals { + org.apache.coyote.Constants.SENDFILE_SUPPORTED_ATTR; + + ++ /** ++ * The request attribute that is set to the value of {@code Boolean.TRUE} ++ * if {@link org.apache.catalina.filters.RemoteIpFilter} determines ++ * that this request was submitted via a secure channel. ++ */ ++ public static final String REMOTE_IP_FILTER_SECURE = "org.apache.catalina.filters.RemoteIpFilter.secure"; ++ ++ + /** + * The request attribute that can be used by a servlet to pass + * to the connector the name of the file that is to be served +diff --git a/java/org/apache/catalina/connector/Request.java b/java/org/apache/catalina/connector/Request.java +index 94065ef..889d5e7 100644 +--- a/java/org/apache/catalina/connector/Request.java ++++ b/java/org/apache/catalina/connector/Request.java +@@ -3501,6 +3501,20 @@ public class Request implements HttpServletRequest { + // NO-OP + } + }); ++ specialAttributes.put(Globals.REMOTE_IP_FILTER_SECURE, ++ new SpecialAttributeAdapter() { ++ @Override ++ public Object get(Request request, String name) { ++ return Boolean.valueOf(request.isSecure()); ++ } ++ ++ @Override ++ public void set(Request request, String name, Object value) { ++ if (value instanceof Boolean) { ++ request.setSecure(((Boolean) value).booleanValue()); ++ } ++ } ++ }); + specialAttributes.put(Globals.STREAM_ID, + new SpecialAttributeAdapter() { + @Override +diff --git a/java/org/apache/catalina/filters/RemoteIpFilter.java b/java/org/apache/catalina/filters/RemoteIpFilter.java +index b9f6655..e978cfb 100644 +--- a/java/org/apache/catalina/filters/RemoteIpFilter.java ++++ b/java/org/apache/catalina/filters/RemoteIpFilter.java +@@ -577,11 +577,6 @@ public class RemoteIpFilter extends GenericFilter { + return serverPort; + } + +- @Override +- public boolean isSecure() { +- return secure; +- } +- + public void removeHeader(String name) { + Map.Entry> header = getHeaderEntry(name); + if (header != null) { +@@ -617,7 +612,7 @@ public class RemoteIpFilter extends GenericFilter { + } + + public void setSecure(boolean secure) { +- this.secure = secure; ++ super.getRequest().setAttribute(Globals.REMOTE_IP_FILTER_SECURE, Boolean.valueOf(secure)); + } + + public void setServerPort(int serverPort) { +diff --git a/test/org/apache/catalina/filters/TestRemoteIpFilter.java b/test/org/apache/catalina/filters/TestRemoteIpFilter.java +index f7f2093..109fdd2 100644 +--- a/test/org/apache/catalina/filters/TestRemoteIpFilter.java ++++ b/test/org/apache/catalina/filters/TestRemoteIpFilter.java +@@ -81,15 +81,21 @@ public class TestRemoteIpFilter extends TomcatBaseTest { + + private static final long serialVersionUID = 1L; + +- private transient HttpServletRequest request; +- +- public HttpServletRequest getRequest() { +- return request; +- } ++ public String remoteAddr; ++ public String remoteHost; ++ public String scheme; ++ public String serverName; ++ public int serverPort; ++ public boolean isSecure; + + @Override + public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { +- this.request = request; ++ this.isSecure = request.isSecure(); ++ this.remoteAddr = request.getRemoteAddr(); ++ this.remoteHost = request.getRemoteHost(); ++ this.scheme = request.getScheme(); ++ this.serverName = request.getServerName(); ++ this.serverPort = request.getServerPort(); + PrintWriter writer = response.getWriter(); + + writer.println("request.remoteAddr=" + request.getRemoteAddr()); +@@ -127,16 +133,6 @@ public class TestRemoteIpFilter extends TomcatBaseTest { + getCoyoteRequest().scheme().setString(scheme); + } + +- @Override +- public void setAttribute(String name, Object value) { +- getCoyoteRequest().getAttributes().put(name, value); +- } +- +- @Override +- public Object getAttribute(String name) { +- return getCoyoteRequest().getAttributes().get(name); +- } +- + @Override + public String getServerName() { + return "localhost"; +@@ -667,16 +663,70 @@ public class TestRemoteIpFilter extends TomcatBaseTest { + + // VALIDATE + Assert.assertEquals(HttpURLConnection.HTTP_OK, httpURLConnection.getResponseCode()); +- HttpServletRequest request = mockServlet.getRequest(); +- Assert.assertNotNull(request); + + // VALIDATE X-FORWARDED-FOR +- Assert.assertEquals(expectedRemoteAddr, request.getRemoteAddr()); +- Assert.assertEquals(expectedRemoteAddr, request.getRemoteHost()); ++ Assert.assertEquals(expectedRemoteAddr, mockServlet.remoteAddr); ++ Assert.assertEquals(expectedRemoteAddr, mockServlet.remoteHost); + + // VALIDATE X-FORWARDED-PROTO +- Assert.assertTrue(request.isSecure()); +- Assert.assertEquals("https", request.getScheme()); +- Assert.assertEquals(443, request.getServerPort()); ++ Assert.assertTrue(mockServlet.isSecure); ++ Assert.assertEquals("https", mockServlet.scheme); ++ Assert.assertEquals(443, mockServlet.serverPort); ++ } ++ ++ @Test ++ public void testJSessionIdSecureAttributeMissing() throws Exception { ++ ++ // mostly default configuration : enable "x-forwarded-proto" ++ Map remoteIpFilterParameter = new HashMap<>(); ++ remoteIpFilterParameter.put("protocolHeader", "x-forwarded-proto"); ++ ++ // SETUP ++ Tomcat tomcat = getTomcatInstance(); ++ Context root = tomcat.addContext("", TEMP_DIR); ++ ++ FilterDef filterDef = new FilterDef(); ++ filterDef.getParameterMap().putAll(remoteIpFilterParameter); ++ filterDef.setFilterClass(RemoteIpFilter.class.getName()); ++ filterDef.setFilterName(RemoteIpFilter.class.getName()); ++ ++ root.addFilterDef(filterDef); ++ ++ FilterMap filterMap = new FilterMap(); ++ filterMap.setFilterName(RemoteIpFilter.class.getName()); ++ filterMap.addURLPatternDecoded("*"); ++ root.addFilterMap(filterMap); ++ ++ Bug66471Servlet bug66471Servlet = new Bug66471Servlet(); ++ ++ Tomcat.addServlet(root, bug66471Servlet.getClass().getName(), bug66471Servlet); ++ root.addServletMappingDecoded("/test", bug66471Servlet.getClass().getName()); ++ ++ getTomcatInstance().start(); ++ ++ Map> resHeaders = new HashMap<>(); ++ Map> reqHeaders = new HashMap<>(); ++ String expectedRemoteAddr = "my-remote-addr"; ++ List forwardedFor = new ArrayList<>(1); ++ forwardedFor.add(expectedRemoteAddr); ++ List forwardedProto = new ArrayList<>(1); ++ forwardedProto.add("https"); ++ reqHeaders.put("x-forwarded-for", forwardedFor); ++ reqHeaders.put("x-forwarded-proto", forwardedProto); ++ ++ getUrl("http://localhost:" + tomcat.getConnector().getLocalPort() + ++ "/test", null, reqHeaders, resHeaders); ++ String setCookie = resHeaders.get("Set-Cookie").get(0); ++ Assert.assertTrue(setCookie.contains("Secure")); ++ Assert.assertTrue(bug66471Servlet.isSecure.booleanValue()); ++ } ++ public static class Bug66471Servlet extends HttpServlet { ++ private static final long serialVersionUID = 1L; ++ public Boolean isSecure; ++ @Override ++ protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { ++ req.getSession(); ++ isSecure = (Boolean) req.getAttribute(Globals.REMOTE_IP_FILTER_SECURE); ++ } + } + } +diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml +index 8837628..15be3ed 100644 +--- a/webapps/docs/changelog.xml ++++ b/webapps/docs/changelog.xml +@@ -478,6 +478,11 @@ + Improve handling of overflow in the UTF-8 decoder with supplementary + characters. (markt) + ++ ++ 66471: Fix JSessionId secure attribute missing When ++ RemoteIpFilter determines that this request was submitted ++ via a secure channel. (lihan) ++ + +
+ +-- +2.33.0 + diff --git a/tomcat.spec b/tomcat.spec index c3e0790..3612739 100644 --- a/tomcat.spec +++ b/tomcat.spec @@ -13,7 +13,7 @@ Name: tomcat Epoch: 1 Version: %{major_version}.%{minor_version}.%{micro_version} -Release: 29 +Release: 30 Summary: Implementation of the Java Servlet, JavaServer Pages, Java Expression Language and Java WebSocket technologies License: ASL 2.0 URL: http://tomcat.apache.org/ @@ -102,6 +102,8 @@ Patch6057: CVE-2021-41079.patch Patch6058: CVE-2021-42340.patch Patch6069: CVE-2022-23181.patch Patch6070: CVE-2022-42252.patch +Patch6071: CVE-2023-28708-pre.patch +Patch6072: CVE-2023-28708.patch BuildRequires: ecj >= 1:4.6.1 findutils apache-commons-collections apache-commons-daemon BuildRequires: apache-commons-dbcp apache-commons-pool tomcat-taglibs-standard ant @@ -503,6 +505,9 @@ fi %{_javadocdir}/%{name} %changelog +* Mon Apr 17 2023 wangkai <13474090681@163.com> - 1:9.0.10-30 +- Fix CVE-2023-28708 + * Wed Dec 21 2022 xulei - 1:9.0.10-29 - Fix CVE-2022-42252