diff --git a/CVE-2023-28708.patch b/CVE-2023-28708.patch new file mode 100644 index 0000000000000000000000000000000000000000..9c79aa0edca99a8a78df09fa29dbbf90014ee921 --- /dev/null +++ b/CVE-2023-28708.patch @@ -0,0 +1,235 @@ +From 438ef4fef4e33bfd5779f906c73865b7ae494ad1 Mon Sep 17 00:00:00 2001 +From: mayp +Date: Tue, 11 Apr 2023 14:30:35 +0800 +Subject: [PATCH] Please enter the commit message for your changes. Lines + starting with '' will be ignored, and an empty message aborts the commit. + + On branch master + Changes to be committed: + modified: java/org/apache/catalina/Globals.java + modified: java/org/apache/catalina/connector/Request.java + modified: java/org/apache/catalina/filters/RemoteIpFilter.java + modified: test/org/apache/catalina/filters/TestRemoteIpFilter.java + modified: webapps/docs/changelog.xml +--- + java/org/apache/catalina/Globals.java | 7 ++ + .../apache/catalina/connector/Request.java | 14 +++ + .../catalina/filters/RemoteIpFilter.java | 7 +- + .../catalina/filters/TestRemoteIpFilter.java | 96 ++++++++++++++----- + webapps/docs/changelog.xml | 5 + + 5 files changed, 100 insertions(+), 29 deletions(-) + +diff --git a/java/org/apache/catalina/Globals.java b/java/org/apache/catalina/Globals.java +index 994902b..5b4cad6 100644 +--- a/java/org/apache/catalina/Globals.java ++++ b/java/org/apache/catalina/Globals.java +@@ -144,6 +144,13 @@ 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 c4cc26a..dd4c881 100644 +--- a/java/org/apache/catalina/connector/Request.java ++++ b/java/org/apache/catalina/connector/Request.java +@@ -3487,6 +3487,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()); ++ } ++ } ++ }); + + for (SimpleDateFormat sdf : formatsTemplate) { + sdf.setTimeZone(GMT_ZONE); +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 a97e15d..6a95e37 100644 +--- a/webapps/docs/changelog.xml ++++ b/webapps/docs/changelog.xml +@@ -60,6 +60,11 @@ + searching for nested groups when the JNDIRealm is configured with + roleNested set to true. (markt) + ++ ++ 66471: Fix JSessionId secure attribute missing When ++ RemoteIpFilter determines that this request was submitted ++ via a secure channel. (lihan) ++ + + Add connection pooling to JNDI realm. (remm) + +-- +2.36.1 + diff --git a/tomcat.spec b/tomcat.spec index 8faa8b89be95768482ab145dd97e92ed7f54a8fd..6b99f824ac645706784656eb18164aa20db78b64 100644 --- a/tomcat.spec +++ b/tomcat.spec @@ -13,7 +13,7 @@ Name: tomcat Epoch: 1 Version: %{major_version}.%{minor_version}.%{micro_version} -Release: 26 +Release: 27 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,7 @@ Patch6057: CVE-2021-41079.patch Patch6058: CVE-2021-42340.patch Patch6059: CVE-2022-23181.patch Patch6060: CVE-2022-42252.patch +Patch6061: 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 +504,9 @@ fi %{_javadocdir}/%{name} %changelog +* Tue Apr 11 2023 mayp 1:9.0.10-27 +- Fix CVE-2023-28708 + * Sun Jan 29 2023 yaoxin 1:9.0.10-26 - Fix CVE-2022-42252