diff --git a/CVE-2025-46701-1.patch b/CVE-2025-46701-1.patch new file mode 100644 index 0000000000000000000000000000000000000000..e2c047ff7d43266d9ec6c43486377ff083e7f8b8 --- /dev/null +++ b/CVE-2025-46701-1.patch @@ -0,0 +1,384 @@ +From 8df00018a252baa9497615d6420fb6c10466fa74 Mon Sep 17 00:00:00 2001 +From: Mark Thomas +Date: Mon, 28 Apr 2025 12:58:21 +0100 +Subject: [PATCH] Refactor CGI servlet to access resources via WebResources + +Origin: https://github.com/apache/tomcat/commit/8df00018a252baa9497615d6420fb6c10466fa74 +--- + .../apache/catalina/servlets/CGIServlet.java | 228 +++++++----------- + .../catalina/servlets/LocalStrings.properties | 1 - + .../servlets/LocalStrings_fr.properties | 1 - + .../servlets/LocalStrings_ja.properties | 1 - + .../servlets/LocalStrings_ko.properties | 1 - + .../servlets/LocalStrings_zh_CN.properties | 1 - + 6 files changed, 90 insertions(+), 143 deletions(-) + +diff --git a/java/org/apache/catalina/servlets/CGIServlet.java b/java/org/apache/catalina/servlets/CGIServlet.java +index b825920..e8e9f62 100644 +--- a/java/org/apache/catalina/servlets/CGIServlet.java ++++ b/java/org/apache/catalina/servlets/CGIServlet.java +@@ -24,6 +24,8 @@ import java.io.InputStream; + import java.io.InputStreamReader; + import java.io.OutputStream; + import java.io.UnsupportedEncodingException; ++import java.net.MalformedURLException; ++import java.net.URL; + import java.net.URLDecoder; + import java.nio.file.Files; + import java.util.ArrayList; +@@ -622,9 +624,6 @@ public final class CGIServlet extends HttpServlet { + /** pathInfo for the current request */ + private String pathInfo = null; + +- /** real file system directory of the enclosing servlet's web app */ +- private String webAppRootDir = null; +- + /** tempdir for context - used to expand scripts in unexpanded wars */ + private File tmpDir = null; + +@@ -678,7 +677,6 @@ public final class CGIServlet extends HttpServlet { + */ + protected void setupFromContext(ServletContext context) { + this.context = context; +- this.webAppRootDir = context.getRealPath("/"); + this.tmpDir = (File) context.getAttribute(ServletContext.TEMPDIR); + } + +@@ -785,10 +783,9 @@ public final class CGIServlet extends HttpServlet { + * cgiPathPrefix is defined by setting this servlet's cgiPathPrefix init parameter + *

+ * +- * @param pathInfo String from HttpServletRequest.getPathInfo() +- * @param webAppRootDir String from context.getRealPath("/") + * @param contextPath String as from HttpServletRequest.getContextPath() + * @param servletPath String as from HttpServletRequest.getServletPath() ++ * @param pathInfo String from HttpServletRequest.getPathInfo() + * @param cgiPathPrefix subdirectory of webAppRootDir below which the web app's CGIs may be stored; can be null. + * The CGI search path will start at webAppRootDir + File.separator + cgiPathPrefix (or + * webAppRootDir alone if cgiPathPrefix is null). cgiPathPrefix is defined by setting +@@ -805,57 +802,105 @@ public final class CGIServlet extends HttpServlet { + * found + * + */ +- protected String[] findCGI(String pathInfo, String webAppRootDir, String contextPath, String servletPath, +- String cgiPathPrefix) { +- String path = null; +- String name = null; +- String scriptname = null; ++ protected String[] findCGI(String contextPath, String servletPath, String pathInfo, String cgiPathPrefix) { + +- if (webAppRootDir.lastIndexOf(File.separator) == (webAppRootDir.length() - 1)) { +- // strip the trailing "/" from the webAppRootDir +- webAppRootDir = webAppRootDir.substring(0, (webAppRootDir.length() - 1)); +- } ++ StringBuilder cgiPath = new StringBuilder(); ++ StringBuilder urlPath = new StringBuilder(); + +- if (cgiPathPrefix != null) { +- webAppRootDir = webAppRootDir + File.separator + cgiPathPrefix; +- } ++ URL cgiScriptURL = null; + +- if (log.isTraceEnabled()) { +- log.trace(sm.getString("cgiServlet.find.path", pathInfo, webAppRootDir)); ++ if (cgiPathPrefix == null || cgiPathPrefix.isEmpty()) { ++ cgiPath.append(servletPath); ++ } else { ++ cgiPath.append('/'); ++ cgiPath.append(cgiPathPrefix); + } ++ urlPath.append(servletPath); + +- File currentLocation = new File(webAppRootDir); +- StringTokenizer dirWalker = new StringTokenizer(pathInfo, "/"); +- if (log.isTraceEnabled()) { +- log.trace(sm.getString("cgiServlet.find.location", currentLocation.getAbsolutePath())); +- } +- StringBuilder cginameBuilder = new StringBuilder(); +- while (!currentLocation.isFile() && dirWalker.hasMoreElements()) { +- String nextElement = (String) dirWalker.nextElement(); +- currentLocation = new File(currentLocation, nextElement); +- cginameBuilder.append('/').append(nextElement); ++ StringTokenizer pathWalker = new StringTokenizer(pathInfo, "/"); ++ ++ while (pathWalker.hasMoreElements() && cgiScriptURL == null) { ++ String urlSegment = pathWalker.nextToken(); ++ cgiPath.append('/'); ++ cgiPath.append(urlSegment); ++ urlPath.append('/'); ++ urlPath.append(urlSegment); + if (log.isTraceEnabled()) { +- log.trace(sm.getString("cgiServlet.find.location", currentLocation.getAbsolutePath())); ++ log.trace(sm.getString("cgiServlet.find.location", cgiPath.toString())); ++ } ++ try { ++ cgiScriptURL = context.getResource(cgiPath.toString()); ++ } catch (MalformedURLException e) { ++ // Ignore - should never happen + } + } +- String cginame = cginameBuilder.toString(); +- if (!currentLocation.isFile()) { ++ ++ // No script was found ++ if (cgiScriptURL == null) { + return new String[] { null, null, null, null }; + } + +- path = currentLocation.getAbsolutePath(); +- name = currentLocation.getName(); ++ // Set-up return values ++ String path = null; ++ String scriptName = null; ++ String cgiName = null; ++ String name = null; + +- if (servletPath.startsWith(cginame)) { +- scriptname = contextPath + cginame; +- } else { +- scriptname = contextPath + servletPath + cginame; ++ path = context.getRealPath(cgiPath.toString()); ++ if (path == null) { ++ /* ++ * The script doesn't exist directly on the file system. It might be located in an archive or similar. ++ * Such scripts are extracted to the web application's temporary file location. ++ */ ++ File tmpCgiFile = new File(tmpDir + cgiPath.toString()); ++ if (!tmpCgiFile.exists()) { ++ ++ // Create directories ++ File parent = tmpCgiFile.getParentFile(); ++ if (!parent.mkdirs() && !parent.isDirectory()) { ++ log.warn(sm.getString("cgiServlet.expandCreateDirFail", parent.getAbsolutePath())); ++ return new String[] { null, null, null, null }; ++ } ++ ++ try (InputStream is = context.getResourceAsStream(cgiPath.toString())) { ++ synchronized (expandFileLock) { ++ // Check if file was created by concurrent request ++ if (!tmpCgiFile.exists()) { ++ try { ++ Files.copy(is, tmpCgiFile.toPath()); ++ } catch (IOException ioe) { ++ log.warn(sm.getString("cgiServlet.expandFail", cgiScriptURL, ++ tmpCgiFile.getAbsolutePath()), ioe); ++ if (tmpCgiFile.exists()) { ++ if (!tmpCgiFile.delete()) { ++ log.warn(sm.getString("cgiServlet.expandDeleteFail", ++ tmpCgiFile.getAbsolutePath())); ++ } ++ } ++ return new String[] { null, null, null, null }; ++ } ++ if (log.isDebugEnabled()) { ++ log.debug(sm.getString("cgiServlet.expandOk", cgiScriptURL, ++ tmpCgiFile.getAbsolutePath())); ++ } ++ } ++ } ++ } catch (IOException ioe) { ++ log.warn(sm.getString("cgiServlet.expandCloseFail", cgiScriptURL), ioe); ++ } ++ } ++ path = tmpCgiFile.getAbsolutePath(); + } + ++ scriptName = urlPath.toString(); ++ cgiName = scriptName.substring(servletPath.length()); ++ name = scriptName.substring(scriptName.lastIndexOf('/') + 1); ++ + if (log.isTraceEnabled()) { +- log.trace(sm.getString("cgiServlet.find.found", name, path, scriptname, cginame)); ++ log.trace(sm.getString("cgiServlet.find.found", name, path, scriptName, cgiName)); + } +- return new String[] { path, scriptname, cginame, name }; ++ ++ return new String[] { path, scriptName, cgiName, name }; + } + + /** +@@ -892,13 +937,7 @@ public final class CGIServlet extends HttpServlet { + sPathInfoOrig = this.pathInfo; + sPathInfoOrig = sPathInfoOrig == null ? "" : sPathInfoOrig; + +- if (webAppRootDir == null) { +- // The app has not been deployed in exploded form +- webAppRootDir = tmpDir.toString(); +- expandCGIScript(); +- } +- +- sCGINames = findCGI(sPathInfoOrig, webAppRootDir, contextPath, servletPath, cgiPathPrefix); ++ sCGINames = findCGI(contextPath, servletPath, sPathInfoOrig, cgiPathPrefix); + + sCGIFullPath = sCGINames[0]; + sCGIScriptName = sCGINames[1]; +@@ -1025,93 +1064,6 @@ public final class CGIServlet extends HttpServlet { + return true; + } + +- /** +- * Extracts requested resource from web app archive to context work directory to enable CGI script to be +- * executed. +- */ +- protected void expandCGIScript() { +- StringBuilder srcPath = new StringBuilder(); +- StringBuilder destPath = new StringBuilder(); +- InputStream is = null; +- +- // paths depend on mapping +- if (cgiPathPrefix == null) { +- srcPath.append(pathInfo); +- is = context.getResourceAsStream(srcPath.toString()); +- destPath.append(tmpDir); +- destPath.append(pathInfo); +- } else { +- // essentially same search algorithm as findCGI() +- srcPath.append(cgiPathPrefix); +- StringTokenizer pathWalker = new StringTokenizer(pathInfo, "/"); +- // start with first element +- while (pathWalker.hasMoreElements() && (is == null)) { +- srcPath.append('/'); +- srcPath.append(pathWalker.nextElement()); +- is = context.getResourceAsStream(srcPath.toString()); +- } +- destPath.append(tmpDir); +- destPath.append('/'); +- destPath.append(srcPath); +- } +- +- if (is == null) { +- // didn't find anything, give up now +- log.warn(sm.getString("cgiServlet.expandNotFound", srcPath)); +- return; +- } +- +- try { +- File f = new File(destPath.toString()); +- if (f.exists()) { +- // Don't need to expand if it already exists +- return; +- } +- +- // create directories +- File dir = f.getParentFile(); +- if (!dir.mkdirs() && !dir.isDirectory()) { +- log.warn(sm.getString("cgiServlet.expandCreateDirFail", dir.getAbsolutePath())); +- return; +- } +- +- try { +- synchronized (expandFileLock) { +- // make sure file doesn't exist +- if (f.exists()) { +- return; +- } +- +- // create file +- if (!f.createNewFile()) { +- return; +- } +- +- Files.copy(is, f.toPath()); +- +- if (log.isDebugEnabled()) { +- log.debug(sm.getString("cgiServlet.expandOk", srcPath, destPath)); +- } +- } +- } catch (IOException ioe) { +- log.warn(sm.getString("cgiServlet.expandFail", srcPath, destPath), ioe); +- // delete in case file is corrupted +- if (f.exists()) { +- if (!f.delete()) { +- log.warn(sm.getString("cgiServlet.expandDeleteFail", f.getAbsolutePath())); +- } +- } +- } +- } finally { +- try { +- is.close(); +- } catch (IOException e) { +- log.warn(sm.getString("cgiServlet.expandCloseFail", srcPath), e); +- } +- } +- } +- +- + /** + * Returns important CGI environment information in a multi-line text format. + * +@@ -1413,9 +1365,9 @@ public final class CGIServlet extends HttpServlet { + *
  • Allowed characters in path segments: This implementation does not allow non-terminal NULL segments + * in the the path -- IOExceptions may be thrown; + *
  • "." and ".." path segments: This implementation does not allow +- * "." and ".." in the the path, and such characters will result in an IOException +- * being thrown (this should never happen since Tomcat normalises the requestURI before determining the +- * contextPath, servletPath and pathInfo); ++ * "." and ".." in the path, and such characters will result in an IOException being ++ * thrown (this should never happen since Tomcat normalises the requestURI before determining the contextPath, ++ * servletPath and pathInfo); + *
  • Implementation limitations: This implementation does not impose any limitations except as + * documented above. This implementation may be limited by the servlet container used to house this + * implementation. In particular, all the primary CGI variable values are derived either directly or indirectly +diff --git a/java/org/apache/catalina/servlets/LocalStrings.properties b/java/org/apache/catalina/servlets/LocalStrings.properties +index b869d08..cf72066 100644 +--- a/java/org/apache/catalina/servlets/LocalStrings.properties ++++ b/java/org/apache/catalina/servlets/LocalStrings.properties +@@ -21,7 +21,6 @@ cgiServlet.expandCloseFail=Failed to close input stream for script at path [{0}] + cgiServlet.expandCreateDirFail=Failed to create destination directory [{0}] for script expansion + cgiServlet.expandDeleteFail=Failed to delete file at [{0}] after IOException during expansion + cgiServlet.expandFail=Failed to expand script at path [{0}] to [{1}] +-cgiServlet.expandNotFound=Unable to expand [{0}] as it could not be found + cgiServlet.expandOk=Expanded script at path [{0}] to [{1}] + cgiServlet.find.found=Found CGI: name [{0}], path [{1}], script name [{2}] and CGI name [{3}] + cgiServlet.find.location=Looking for a file at [{0}] +diff --git a/java/org/apache/catalina/servlets/LocalStrings_fr.properties b/java/org/apache/catalina/servlets/LocalStrings_fr.properties +index abf744b..137b3f6 100644 +--- a/java/org/apache/catalina/servlets/LocalStrings_fr.properties ++++ b/java/org/apache/catalina/servlets/LocalStrings_fr.properties +@@ -21,7 +21,6 @@ cgiServlet.expandCloseFail=Impossible de fermer le flux d''entrée du script ave + cgiServlet.expandCreateDirFail=Echec de la création du répertoire de destination [{0}] pour la décompression du script + cgiServlet.expandDeleteFail=Impossible d''effacer le fichier [{0}] suite à une IOException pendant la décompression + cgiServlet.expandFail=Impossible de faire l''expansion du script au chemin [{0}] vers [{1}] +-cgiServlet.expandNotFound=Impossible de décompresser [{0}] car il n''a pas été trouvé + cgiServlet.expandOk=Extrait le script du chemin [{0}] vers [{1}] + cgiServlet.find.found=Trouvé le CGI : nom [{0}], chemin [{1}], nom de script [{2}] et nom du CGI [{3}] + cgiServlet.find.location=Recherche d''un fichier en [{0}] +diff --git a/java/org/apache/catalina/servlets/LocalStrings_ja.properties b/java/org/apache/catalina/servlets/LocalStrings_ja.properties +index c56a57b..4ae874e 100644 +--- a/java/org/apache/catalina/servlets/LocalStrings_ja.properties ++++ b/java/org/apache/catalina/servlets/LocalStrings_ja.properties +@@ -21,7 +21,6 @@ cgiServlet.expandCloseFail=パス [{0}] のスクリプトの入力ストリー + cgiServlet.expandCreateDirFail=スクリプトの展開先ディレクトリ[{0}]の作成に失敗しました。 + cgiServlet.expandDeleteFail=拡張中にIOExceptionの後に [{0}] でファイルを削除できませんでした + cgiServlet.expandFail=パス [{0}] のスクリプトを [{1}] に展開できませんでした +-cgiServlet.expandNotFound=見つけることができなかったため [{0}] を展開できません + cgiServlet.expandOk=パス [{0}] の [{1}] に展開されたスクリプト + cgiServlet.find.found=見つかったCGI: 名前 [{0}]、パス [{1}]、スクリプト名 [{2}]、CGI名 [{3}] + cgiServlet.find.location=ファイル [{0}] を探しています。 +diff --git a/java/org/apache/catalina/servlets/LocalStrings_ko.properties b/java/org/apache/catalina/servlets/LocalStrings_ko.properties +index aeb3d72..547c842 100644 +--- a/java/org/apache/catalina/servlets/LocalStrings_ko.properties ++++ b/java/org/apache/catalina/servlets/LocalStrings_ko.properties +@@ -21,7 +21,6 @@ cgiServlet.expandCloseFail=경로 [{0}]에 위치한 스크립트를 위한, 입 + cgiServlet.expandCreateDirFail=스크립트를 압축해제 하기 위한 대상 디렉토리 [{0}]을(를) 생성하지 못했습니다. + cgiServlet.expandDeleteFail=압축해제 중 IOException이 발생한 후, [{0}]에 위치한 해당 파일을 삭제하지 못했습니다. + cgiServlet.expandFail=경로 [{0}]의 스크립트를 [{1}](으)로 압축해제 하지 못했습니다. +-cgiServlet.expandNotFound=[{0}]을(를) 찾을 수 없어서 압축해제 할 수 없습니다. + cgiServlet.expandOk=[{0}] 경로에 있는 스트립트가 [{1}](으)로 압축 해제되었습니다. + cgiServlet.find.found=CGI 발견: 이름 [{0}], 경로 [{1}], 스크립트 이름 [{2}], CGI 이름 [{3}] + cgiServlet.find.location=[{0}]에 위치한 파일을 찾는 중 +diff --git a/java/org/apache/catalina/servlets/LocalStrings_zh_CN.properties b/java/org/apache/catalina/servlets/LocalStrings_zh_CN.properties +index 72ee5c9..700617c 100644 +--- a/java/org/apache/catalina/servlets/LocalStrings_zh_CN.properties ++++ b/java/org/apache/catalina/servlets/LocalStrings_zh_CN.properties +@@ -21,7 +21,6 @@ cgiServlet.expandCloseFail=无法关闭路径[{0}]处脚本的输入流 + cgiServlet.expandCreateDirFail=无法为脚本扩展创建目标目录[{0}] + cgiServlet.expandDeleteFail=扩展期间,发生IOException异常后删除文件[{0}]失败 + cgiServlet.expandFail=在路径[{0}] 到[{1}] 展开脚本失败. +-cgiServlet.expandNotFound=无法展开[{0}],因为找不到它。 + cgiServlet.expandOk=从路径[{0}]到[{1}]扩展脚本 + cgiServlet.find.found=找到CGI:name[{0}]、path[{1}]、script name[{2}]和CGI name[{3}] + cgiServlet.find.location=在 [{0}] 查找文件 +-- +2.49.0 + diff --git a/CVE-2025-46701-2.patch b/CVE-2025-46701-2.patch new file mode 100644 index 0000000000000000000000000000000000000000..b4332980fb50413782007e1d2fc2fcca68e26b7f --- /dev/null +++ b/CVE-2025-46701-2.patch @@ -0,0 +1,160 @@ +From 8cb95ff03221067c511b3fa66d4f745bc4b0a605 Mon Sep 17 00:00:00 2001 +From: Mark Thomas +Date: Fri, 2 May 2025 16:42:30 +0100 +Subject: [PATCH] Use WebResource API to differentiate files and directories + +It is much easier/more efficient to do this directly than via the +ServletContext API. + +Origin: https://github.com/apache/tomcat/commit/8cb95ff03221067c511b3fa66d4f745bc4b0a605 +--- + .../apache/catalina/servlets/CGIServlet.java | 37 +++++++++++-------- + .../catalina/servlets/LocalStrings.properties | 1 + + 2 files changed, 23 insertions(+), 15 deletions(-) + +diff --git a/java/org/apache/catalina/servlets/CGIServlet.java b/java/org/apache/catalina/servlets/CGIServlet.java +index e8e9f62..f7b2563 100644 +--- a/java/org/apache/catalina/servlets/CGIServlet.java ++++ b/java/org/apache/catalina/servlets/CGIServlet.java +@@ -24,8 +24,6 @@ import java.io.InputStream; + import java.io.InputStreamReader; + import java.io.OutputStream; + import java.io.UnsupportedEncodingException; +-import java.net.MalformedURLException; +-import java.net.URL; + import java.net.URLDecoder; + import java.nio.file.Files; + import java.util.ArrayList; +@@ -44,12 +42,16 @@ import javax.servlet.RequestDispatcher; + import javax.servlet.ServletConfig; + import javax.servlet.ServletContext; + import javax.servlet.ServletException; ++import javax.servlet.UnavailableException; + import javax.servlet.http.Cookie; + import javax.servlet.http.HttpServlet; + import javax.servlet.http.HttpServletRequest; + import javax.servlet.http.HttpServletResponse; + import javax.servlet.http.HttpSession; + ++import org.apache.catalina.Globals; ++import org.apache.catalina.WebResource; ++import org.apache.catalina.WebResourceRoot; + import org.apache.catalina.util.IOTools; + import org.apache.juli.logging.Log; + import org.apache.juli.logging.LogFactory; +@@ -244,6 +246,8 @@ public final class CGIServlet extends HttpServlet { + private Set cgiMethods = new HashSet<>(); + private boolean cgiMethodsAll = false; + ++ private transient WebResourceRoot resources = null; ++ + + /** + * The time (in milliseconds) to wait for the reading of stderr to complete before terminating the CGI process. +@@ -379,6 +383,13 @@ public final class CGIServlet extends HttpServlet { + } else if (value != null) { + cmdLineArgumentsDecodedPattern = Pattern.compile(value); + } ++ ++ // Load the web resources ++ resources = (WebResourceRoot) getServletContext().getAttribute(Globals.RESOURCES_ATTR); ++ ++ if (resources == null) { ++ throw new UnavailableException(sm.getString("cgiServlet.noResources")); ++ } + } + + +@@ -807,7 +818,7 @@ public final class CGIServlet extends HttpServlet { + StringBuilder cgiPath = new StringBuilder(); + StringBuilder urlPath = new StringBuilder(); + +- URL cgiScriptURL = null; ++ WebResource cgiScript = null; + + if (cgiPathPrefix == null || cgiPathPrefix.isEmpty()) { + cgiPath.append(servletPath); +@@ -819,7 +830,7 @@ public final class CGIServlet extends HttpServlet { + + StringTokenizer pathWalker = new StringTokenizer(pathInfo, "/"); + +- while (pathWalker.hasMoreElements() && cgiScriptURL == null) { ++ while (pathWalker.hasMoreElements() && (cgiScript == null || !cgiScript.isFile())) { + String urlSegment = pathWalker.nextToken(); + cgiPath.append('/'); + cgiPath.append(urlSegment); +@@ -828,15 +839,11 @@ public final class CGIServlet extends HttpServlet { + if (log.isTraceEnabled()) { + log.trace(sm.getString("cgiServlet.find.location", cgiPath.toString())); + } +- try { +- cgiScriptURL = context.getResource(cgiPath.toString()); +- } catch (MalformedURLException e) { +- // Ignore - should never happen +- } ++ cgiScript = resources.getResource(cgiPath.toString()); + } + + // No script was found +- if (cgiScriptURL == null) { ++ if (cgiScript == null || !cgiScript.isFile()) { + return new String[] { null, null, null, null }; + } + +@@ -846,7 +853,7 @@ public final class CGIServlet extends HttpServlet { + String cgiName = null; + String name = null; + +- path = context.getRealPath(cgiPath.toString()); ++ path = cgiScript.getCanonicalPath(); + if (path == null) { + /* + * The script doesn't exist directly on the file system. It might be located in an archive or similar. +@@ -862,14 +869,14 @@ public final class CGIServlet extends HttpServlet { + return new String[] { null, null, null, null }; + } + +- try (InputStream is = context.getResourceAsStream(cgiPath.toString())) { ++ try (InputStream is = cgiScript.getInputStream()) { + synchronized (expandFileLock) { + // Check if file was created by concurrent request + if (!tmpCgiFile.exists()) { + try { + Files.copy(is, tmpCgiFile.toPath()); + } catch (IOException ioe) { +- log.warn(sm.getString("cgiServlet.expandFail", cgiScriptURL, ++ log.warn(sm.getString("cgiServlet.expandFail", cgiScript.getURL(), + tmpCgiFile.getAbsolutePath()), ioe); + if (tmpCgiFile.exists()) { + if (!tmpCgiFile.delete()) { +@@ -880,13 +887,13 @@ public final class CGIServlet extends HttpServlet { + return new String[] { null, null, null, null }; + } + if (log.isDebugEnabled()) { +- log.debug(sm.getString("cgiServlet.expandOk", cgiScriptURL, ++ log.debug(sm.getString("cgiServlet.expandOk", cgiScript.getURL(), + tmpCgiFile.getAbsolutePath())); + } + } + } + } catch (IOException ioe) { +- log.warn(sm.getString("cgiServlet.expandCloseFail", cgiScriptURL), ioe); ++ log.warn(sm.getString("cgiServlet.expandCloseFail", cgiScript.getURL()), ioe); + } + } + path = tmpCgiFile.getAbsolutePath(); +diff --git a/java/org/apache/catalina/servlets/LocalStrings.properties b/java/org/apache/catalina/servlets/LocalStrings.properties +index cf72066..da597f2 100644 +--- a/java/org/apache/catalina/servlets/LocalStrings.properties ++++ b/java/org/apache/catalina/servlets/LocalStrings.properties +@@ -29,6 +29,7 @@ cgiServlet.invalidArgumentDecoded=The decoded command line argument [{0}] did no + cgiServlet.invalidArgumentEncoded=The encoded command line argument [{0}] did not match the configured cmdLineArgumentsEncoded pattern [{1}] + cgiServlet.invalidCommand=Illegal Character in CGI command path ('.' or '..') detected, not running CGI [{0}] + cgiServlet.notReady=CGI Servlet is not ready to run ++cgiServlet.noResources=No static resources were found + cgiServlet.runBadHeader=Bad header line [{0}] + cgiServlet.runFail=I/O problems processing CGI + cgiServlet.runHeaderReaderFail=I/O problems closing header reader +-- +2.49.0 + diff --git a/tomcat.spec b/tomcat.spec index fe2cf5523d5e6584b2d4ca461954df184fd2a5b9..2d9dce67f48e83eada386c3d6442cadd2c298d4f 100644 --- a/tomcat.spec +++ b/tomcat.spec @@ -23,7 +23,7 @@ Name: tomcat Epoch: 1 Version: %{major_version}.%{minor_version}.%{micro_version} -Release: 2 +Release: 3 Summary: Apache Servlet/JSP Engine, RI for Servlet %{servletspec}/JSP %{jspspec} API License: Apache-2.0 @@ -56,6 +56,8 @@ Patch9: CVE-2025-31650-2.patch Patch10: CVE-2025-31650-3.patch Patch11: CVE-2025-31651-1.patch Patch12: CVE-2025-31651-2.patch +Patch13: CVE-2025-46701-1.patch +Patch14: CVE-2025-46701-2.patch BuildArch: noarch @@ -422,6 +424,9 @@ fi %{appdir}/docs %changelog +* Wed Jun 04 2025 yaoxin <1024769339@qq.com> 1:9.0.100-3 +- Fix CVE-2025-46701 + * Tue Apr 29 2025 wangkai <13474090681@163.com> - 1:9.0.100-2 - Fix CVE-2025-31650, CVE-2025-31651