import OL pki-servlet-engine-9.0.50-1.el9_2.2
This commit is contained in:
parent
350a122f19
commit
70450851a4
151
SOURCES/rhbz-2314686.patch
Normal file
151
SOURCES/rhbz-2314686.patch
Normal file
@ -0,0 +1,151 @@
|
||||
--- java/org/apache/tomcat/util/net/LocalStrings.properties.orig 2024-10-16 12:53:11.408992714 +0200
|
||||
+++ java/org/apache/tomcat/util/net/LocalStrings.properties 2024-10-16 12:54:21.273625279 +0200
|
||||
@@ -26,6 +26,8 @@
|
||||
channel.nio.ssl.expandNetOutBuffer=Expanding network output buffer to [{0}] bytes
|
||||
channel.nio.ssl.foundHttp=Found an plain text HTTP request on what should be an encrypted TLS connection
|
||||
channel.nio.ssl.handshakeError=Handshake error
|
||||
+channel.nio.ssl.handshakeWrapPending=There is already handshake data waiting to be wrapped
|
||||
+channel.nio.ssl.handshakeWrapQueueTooLong=The queue of handshake data to be wrapped has grown too long
|
||||
channel.nio.ssl.incompleteHandshake=Handshake incomplete, you must complete handshake before reading data.
|
||||
channel.nio.ssl.invalidCloseState=Invalid close state, will not send network data.
|
||||
channel.nio.ssl.invalidStatus=Unexpected status [{0}].
|
||||
--- java/org/apache/tomcat/util/net/SecureNio2Channel.java.orig 2024-10-16 12:53:22.726095181 +0200
|
||||
+++ java/org/apache/tomcat/util/net/SecureNio2Channel.java 2024-10-16 12:54:21.273625279 +0200
|
||||
@@ -54,10 +54,12 @@
|
||||
private static final Log log = LogFactory.getLog(SecureNio2Channel.class);
|
||||
private static final StringManager sm = StringManager.getManager(SecureNio2Channel.class);
|
||||
|
||||
- // Value determined by observation of what the SSL Engine requested in
|
||||
- // various scenarios
|
||||
+ // Value determined by observation of what the SSL Engine requested in various scenarios
|
||||
private static final int DEFAULT_NET_BUFFER_SIZE = 16921;
|
||||
|
||||
+ // Much longer than it should ever need to be but short enough to trigger connection closure if something goes wrong
|
||||
+ private static final int HANDSHAKE_WRAP_QUEUE_LENGTH_LIMIT = 100;
|
||||
+
|
||||
protected final Nio2Endpoint endpoint;
|
||||
|
||||
protected ByteBuffer netInBuffer;
|
||||
@@ -68,6 +70,7 @@
|
||||
protected volatile boolean sniComplete = false;
|
||||
|
||||
private volatile boolean handshakeComplete = false;
|
||||
+ private volatile int handshakeWrapQueueLength = 0;
|
||||
private volatile HandshakeStatus handshakeStatus; //gets set by handshake
|
||||
|
||||
protected boolean closed;
|
||||
@@ -765,6 +768,11 @@
|
||||
//perform any tasks if needed
|
||||
if (unwrap.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
|
||||
tasks();
|
||||
+ } else if (unwrap.getHandshakeStatus() == HandshakeStatus.NEED_WRAP) {
|
||||
+ if (++handshakeWrapQueueLength > HANDSHAKE_WRAP_QUEUE_LENGTH_LIMIT) {
|
||||
+ throw new ExecutionException(
|
||||
+ new IOException(sm.getString("channel.nio.ssl.handshakeWrapQueueTooLong")));
|
||||
+ }
|
||||
}
|
||||
//if we need more network data, then bail out for now.
|
||||
if (unwrap.getStatus() == Status.BUFFER_UNDERFLOW) {
|
||||
@@ -895,6 +903,8 @@
|
||||
if (!netOutBuffer.hasRemaining()) {
|
||||
netOutBuffer.clear();
|
||||
SSLEngineResult result = sslEngine.wrap(src, netOutBuffer);
|
||||
+ // Call to wrap() will have included any required handshake data
|
||||
+ handshakeWrapQueueLength = 0;
|
||||
written = result.bytesConsumed();
|
||||
netOutBuffer.flip();
|
||||
if (result.getStatus() == Status.OK) {
|
||||
@@ -960,6 +970,11 @@
|
||||
//perform any tasks if needed
|
||||
if (unwrap.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
|
||||
tasks();
|
||||
+ } else if (unwrap.getHandshakeStatus() == HandshakeStatus.NEED_WRAP) {
|
||||
+ if (++handshakeWrapQueueLength > HANDSHAKE_WRAP_QUEUE_LENGTH_LIMIT) {
|
||||
+ throw new ExecutionException(new IOException(
|
||||
+ sm.getString("channel.nio.ssl.handshakeWrapQueueTooLong")));
|
||||
+ }
|
||||
}
|
||||
//if we need more network data, then bail out for now.
|
||||
if (unwrap.getStatus() == Status.BUFFER_UNDERFLOW) {
|
||||
@@ -1073,6 +1088,11 @@
|
||||
//perform any tasks if needed
|
||||
if (unwrap.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
|
||||
tasks();
|
||||
+ } else if (unwrap.getHandshakeStatus() == HandshakeStatus.NEED_WRAP) {
|
||||
+ if (++handshakeWrapQueueLength > HANDSHAKE_WRAP_QUEUE_LENGTH_LIMIT) {
|
||||
+ throw new ExecutionException(new IOException(
|
||||
+ sm.getString("channel.nio.ssl.handshakeWrapQueueTooLong")));
|
||||
+ }
|
||||
}
|
||||
//if we need more network data, then bail out for now.
|
||||
if (unwrap.getStatus() == Status.BUFFER_UNDERFLOW) {
|
||||
@@ -1182,6 +1202,8 @@
|
||||
netOutBuffer.clear();
|
||||
// Wrap the source data into the internal buffer
|
||||
SSLEngineResult result = sslEngine.wrap(src, netOutBuffer);
|
||||
+ // Call to wrap() will have included any required handshake data
|
||||
+ handshakeWrapQueueLength = 0;
|
||||
final int written = result.bytesConsumed();
|
||||
netOutBuffer.flip();
|
||||
if (result.getStatus() == Status.OK) {
|
||||
--- java/org/apache/tomcat/util/net/SecureNioChannel.java.orig 2024-10-16 12:53:34.697203568 +0200
|
||||
+++ java/org/apache/tomcat/util/net/SecureNioChannel.java 2024-10-16 12:54:21.274625288 +0200
|
||||
@@ -66,6 +66,7 @@
|
||||
protected boolean sniComplete = false;
|
||||
|
||||
protected boolean handshakeComplete = false;
|
||||
+ protected boolean needHandshakeWrap = false;
|
||||
protected HandshakeStatus handshakeStatus; //gets set by handshake
|
||||
|
||||
protected boolean closed = false;
|
||||
@@ -623,6 +624,14 @@
|
||||
//perform any tasks if needed
|
||||
if (unwrap.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
|
||||
tasks();
|
||||
+ } else if (unwrap.getHandshakeStatus() == HandshakeStatus.NEED_WRAP) {
|
||||
+ if (getOutboundRemaining() == 0) {
|
||||
+ handshakeWrap(true);
|
||||
+ } else if (needHandshakeWrap) {
|
||||
+ throw new IOException(sm.getString("channel.nio.ssl.handshakeWrapPending"));
|
||||
+ } else {
|
||||
+ needHandshakeWrap = true;
|
||||
+ }
|
||||
}
|
||||
//if we need more network data, then bail out for now.
|
||||
if (unwrap.getStatus() == Status.BUFFER_UNDERFLOW) {
|
||||
@@ -712,6 +721,14 @@
|
||||
//perform any tasks if needed
|
||||
if (unwrap.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
|
||||
tasks();
|
||||
+ } else if (unwrap.getHandshakeStatus() == HandshakeStatus.NEED_WRAP) {
|
||||
+ if (getOutboundRemaining() == 0) {
|
||||
+ handshakeWrap(true);
|
||||
+ } else if (needHandshakeWrap) {
|
||||
+ throw new IOException(sm.getString("channel.nio.ssl.handshakeWrapPending"));
|
||||
+ } else {
|
||||
+ needHandshakeWrap = true;
|
||||
+ }
|
||||
}
|
||||
//if we need more network data, then bail out for now.
|
||||
if (unwrap.getStatus() == Status.BUFFER_UNDERFLOW) {
|
||||
@@ -812,6 +829,8 @@
|
||||
netOutBuffer.clear();
|
||||
|
||||
SSLEngineResult result = sslEngine.wrap(src, netOutBuffer);
|
||||
+ // Call to wrap() will have included any required handshake data
|
||||
+ needHandshakeWrap = false;
|
||||
// The number of bytes written
|
||||
int written = result.bytesConsumed();
|
||||
netOutBuffer.flip();
|
||||
--- webapps/docs/changelog.xml.orig 2024-10-16 12:53:48.354327221 +0200
|
||||
+++ webapps/docs/changelog.xml 2024-10-16 12:58:15.205743336 +0200
|
||||
@@ -117,6 +117,9 @@
|
||||
Avoid unnecessary duplicate read registrations for blocking I/O with the
|
||||
NIO connector. (markt)
|
||||
</fix>
|
||||
+ <add>
|
||||
+ Add support for TLS 1.3 client initiated re-keying. (markt)
|
||||
+ </add>
|
||||
</changelog>
|
||||
</subsection>
|
||||
<subsection name="WebSocket">
|
||||
404
SOURCES/rhbz-2332817.patch
Normal file
404
SOURCES/rhbz-2332817.patch
Normal file
@ -0,0 +1,404 @@
|
||||
diff -rupN java/org/apache/catalina/WebResourceLockSet.java java/org/apache/catalina/WebResourceLockSet.java
|
||||
--- java/org/apache/catalina/WebResourceLockSet.java 1970-01-01 02:00:00.000000000 +0200
|
||||
+++ java/org/apache/catalina/WebResourceLockSet.java 2025-01-10 17:22:29.107395000 +0200
|
||||
@@ -0,0 +1,73 @@
|
||||
+/*
|
||||
+ * Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
+ * contributor license agreements. See the NOTICE file distributed with
|
||||
+ * this work for additional information regarding copyright ownership.
|
||||
+ * The ASF licenses this file to You under the Apache License, Version 2.0
|
||||
+ * (the "License"); you may not use this file except in compliance with
|
||||
+ * the License. You may obtain a copy of the License at
|
||||
+ *
|
||||
+ * http://www.apache.org/licenses/LICENSE-2.0
|
||||
+ *
|
||||
+ * Unless required by applicable law or agreed to in writing, software
|
||||
+ * distributed under the License is distributed on an "AS IS" BASIS,
|
||||
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
+ * See the License for the specific language governing permissions and
|
||||
+ * limitations under the License.
|
||||
+ */
|
||||
+package org.apache.catalina;
|
||||
+
|
||||
+import java.util.concurrent.atomic.AtomicInteger;
|
||||
+import java.util.concurrent.locks.ReentrantReadWriteLock;
|
||||
+
|
||||
+/**
|
||||
+ * Interface implemented by {@link WebResourceSet} implementations that wish to provide locking functionality.
|
||||
+ */
|
||||
+public interface WebResourceLockSet {
|
||||
+
|
||||
+ /**
|
||||
+ * Lock the resource at the provided path for reading. The resource is not required to exist. Read locks are not
|
||||
+ * exclusive.
|
||||
+ *
|
||||
+ * @param path The path to the resource to be locked for reading
|
||||
+ *
|
||||
+ * @return The {@link ResourceLock} that must be passed to {@link #unlockForRead(ResourceLock)} to release the lock
|
||||
+ */
|
||||
+ ResourceLock lockForRead(String path);
|
||||
+
|
||||
+ /**
|
||||
+ * Release a read lock from the resource associated with the given {@link ResourceLock}.
|
||||
+ *
|
||||
+ * @param resourceLock The {@link ResourceLock} associated with the resource for which a read lock should be
|
||||
+ * released
|
||||
+ */
|
||||
+ void unlockForRead(ResourceLock resourceLock);
|
||||
+
|
||||
+ /**
|
||||
+ * Lock the resource at the provided path for writing. The resource is not required to exist. Write locks are
|
||||
+ * exclusive.
|
||||
+ *
|
||||
+ * @param path The path to the resource to be locked for writing
|
||||
+ *
|
||||
+ * @return The {@link ResourceLock} that must be passed to {@link #unlockForWrite(ResourceLock)} to release the lock
|
||||
+ */
|
||||
+ ResourceLock lockForWrite(String path);
|
||||
+
|
||||
+ /**
|
||||
+ * Release the write lock from the resource associated with the given {@link ResourceLock}.
|
||||
+ *
|
||||
+ * @param resourceLock The {@link ResourceLock} associated with the resource for which the write lock should be
|
||||
+ * released
|
||||
+ */
|
||||
+ void unlockForWrite(ResourceLock resourceLock);
|
||||
+
|
||||
+
|
||||
+ class ResourceLock {
|
||||
+ public final AtomicInteger count = new AtomicInteger(0);
|
||||
+ public final ReentrantReadWriteLock reentrantLock = new ReentrantReadWriteLock();
|
||||
+ public final String key;
|
||||
+
|
||||
+ public ResourceLock(String key) {
|
||||
+ this.key = key;
|
||||
+ }
|
||||
+ }
|
||||
+}
|
||||
diff -rupN java/org/apache/catalina/webresources/DirResourceSet.java java/org/apache/catalina/webresources/DirResourceSet.java
|
||||
--- java/org/apache/catalina/webresources/DirResourceSet.java 2021-12-09 13:29:38.000000000 +0200
|
||||
+++ java/org/apache/catalina/webresources/DirResourceSet.java 2025-01-17 14:42:08.836344422 +0200
|
||||
@@ -22,24 +22,35 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.StandardCopyOption;
|
||||
+import java.util.HashMap;
|
||||
+import java.util.Locale;
|
||||
+import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
import org.apache.catalina.LifecycleException;
|
||||
import org.apache.catalina.WebResource;
|
||||
+import org.apache.catalina.WebResourceLockSet;
|
||||
import org.apache.catalina.WebResourceRoot;
|
||||
import org.apache.catalina.WebResourceRoot.ResourceSetType;
|
||||
import org.apache.catalina.util.ResourceSet;
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
+import org.apache.tomcat.util.http.RequestUtil;
|
||||
|
||||
/**
|
||||
* Represents a {@link org.apache.catalina.WebResourceSet} based on a directory.
|
||||
*/
|
||||
-public class DirResourceSet extends AbstractFileResourceSet {
|
||||
+public class DirResourceSet extends AbstractFileResourceSet implements WebResourceLockSet {
|
||||
|
||||
private static final Log log = LogFactory.getLog(DirResourceSet.class);
|
||||
|
||||
+ private boolean caseSensitive = true;
|
||||
+
|
||||
+ private Map<String,ResourceLock> resourceLocksByPath = new HashMap<>();
|
||||
+ private Object resourceLocksByPathLock = new Object();
|
||||
+
|
||||
+
|
||||
/**
|
||||
* A no argument constructor is required for this to work with the digester.
|
||||
*/
|
||||
@@ -98,22 +109,33 @@ public class DirResourceSet extends Abst
|
||||
String webAppMount = getWebAppMount();
|
||||
WebResourceRoot root = getRoot();
|
||||
if (path.startsWith(webAppMount)) {
|
||||
- File f = file(path.substring(webAppMount.length()), false);
|
||||
- if (f == null) {
|
||||
- return new EmptyResource(root, path);
|
||||
- }
|
||||
- if (!f.exists()) {
|
||||
- return new EmptyResource(root, path, f);
|
||||
- }
|
||||
- if (f.isDirectory() && path.charAt(path.length() - 1) != '/') {
|
||||
- path = path + '/';
|
||||
+ /*
|
||||
+ * Lock the path for reading until the WebResource has been constructed. The lock prevents concurrent reads
|
||||
+ * and writes (e.g. HTTP GET and PUT / DELETE) for the same path causing corruption of the FileResource
|
||||
+ * where some of the fields are set as if the file exists and some as set as if it does not.
|
||||
+ */
|
||||
+ ResourceLock lock = lockForRead(path);
|
||||
+ try {
|
||||
+ File f = file(path.substring(webAppMount.length()), false);
|
||||
+ if (f == null) {
|
||||
+ return new EmptyResource(root, path);
|
||||
+ }
|
||||
+ if (!f.exists()) {
|
||||
+ return new EmptyResource(root, path, f);
|
||||
+ }
|
||||
+ if (f.isDirectory() && path.charAt(path.length() - 1) != '/') {
|
||||
+ path = path + '/';
|
||||
+ }
|
||||
+ return new FileResource(root, path, f, isReadOnly(), getManifest(), this, lock.key);
|
||||
+ } finally {
|
||||
+ unlockForRead(lock);
|
||||
}
|
||||
- return new FileResource(root, path, f, isReadOnly(), getManifest());
|
||||
} else {
|
||||
return new EmptyResource(root, path);
|
||||
}
|
||||
}
|
||||
|
||||
+
|
||||
@Override
|
||||
public String[] list(String path) {
|
||||
checkPath(path);
|
||||
@@ -251,32 +273,43 @@ public class DirResourceSet extends Abst
|
||||
return false;
|
||||
}
|
||||
|
||||
- File dest = null;
|
||||
String webAppMount = getWebAppMount();
|
||||
- if (path.startsWith(webAppMount)) {
|
||||
+ if (!path.startsWith(webAppMount)) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ File dest = null;
|
||||
+ /*
|
||||
+ * Lock the path for writing until the write is complete. The lock prevents concurrent reads and writes (e.g.
|
||||
+ * HTTP GET and PUT / DELETE) for the same path causing corruption of the FileResource where some of the fields
|
||||
+ * are set as if the file exists and some as set as if it does not.
|
||||
+ */
|
||||
+ ResourceLock lock = lockForWrite(path);
|
||||
+ try {
|
||||
dest = file(path.substring(webAppMount.length()), false);
|
||||
if (dest == null) {
|
||||
return false;
|
||||
}
|
||||
- } else {
|
||||
- return false;
|
||||
- }
|
||||
|
||||
- if (dest.exists() && !overwrite) {
|
||||
- return false;
|
||||
- }
|
||||
|
||||
- try {
|
||||
- if (overwrite) {
|
||||
- Files.copy(is, dest.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||
- } else {
|
||||
- Files.copy(is, dest.toPath());
|
||||
+ if (dest.exists() && !overwrite) {
|
||||
+ return false;
|
||||
+ }
|
||||
+
|
||||
+ try {
|
||||
+ if (overwrite) {
|
||||
+ Files.copy(is, dest.toPath(), StandardCopyOption.REPLACE_EXISTING);
|
||||
+ } else {
|
||||
+ Files.copy(is, dest.toPath());
|
||||
+ }
|
||||
+ } catch (IOException ioe) {
|
||||
+ return false;
|
||||
}
|
||||
- } catch (IOException ioe) {
|
||||
- return false;
|
||||
- }
|
||||
|
||||
- return true;
|
||||
+ return true;
|
||||
+ } finally {
|
||||
+ unlockForWrite(lock);
|
||||
+ }
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -291,6 +324,7 @@ public class DirResourceSet extends Abst
|
||||
@Override
|
||||
protected void initInternal() throws LifecycleException {
|
||||
super.initInternal();
|
||||
+ caseSensitive = isCaseSensitive();
|
||||
// Is this an exploded web application?
|
||||
if (getWebAppMount().equals("")) {
|
||||
// Look for a manifest
|
||||
@@ -304,4 +338,105 @@ public class DirResourceSet extends Abst
|
||||
}
|
||||
}
|
||||
}
|
||||
+
|
||||
+
|
||||
+ /*
|
||||
+ * Determines if this ResourceSet is based on a case sensitive file system or not.
|
||||
+ */
|
||||
+ private boolean isCaseSensitive() {
|
||||
+ try {
|
||||
+ String canonicalPath = getFileBase().getCanonicalPath();
|
||||
+ File upper = new File(canonicalPath.toUpperCase(Locale.ENGLISH));
|
||||
+ if (!canonicalPath.equals(upper.getCanonicalPath())) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ File lower = new File(canonicalPath.toLowerCase(Locale.ENGLISH));
|
||||
+ if (!canonicalPath.equals(lower.getCanonicalPath())) {
|
||||
+ return true;
|
||||
+ }
|
||||
+ /*
|
||||
+ * Both upper and lower case versions of the current fileBase have the same canonical path so the file
|
||||
+ * system must be case insensitive.
|
||||
+ */
|
||||
+ } catch (IOException ioe) {
|
||||
+ log.warn(sm.getString("dirResourceSet.isCaseSensitive.fail", getFileBase().getAbsolutePath()), ioe);
|
||||
+ }
|
||||
+ return false;
|
||||
+ }
|
||||
+ private String getLockKey(String path) {
|
||||
+ // Normalize path to ensure that the same key is used for the same path.
|
||||
+ String normalisedPath = RequestUtil.normalize(path);
|
||||
+ if (caseSensitive) {
|
||||
+ return normalisedPath;
|
||||
+ }
|
||||
+ return normalisedPath.toLowerCase(Locale.ENGLISH);
|
||||
+ }
|
||||
+ @Override
|
||||
+ public ResourceLock lockForRead(String path) {
|
||||
+ String key = getLockKey(path);
|
||||
+ ResourceLock resourceLock = null;
|
||||
+ synchronized (resourceLocksByPathLock) {
|
||||
+ /*
|
||||
+ * Obtain the ResourceLock and increment the usage count inside the sync to ensure that that map always has
|
||||
+ * a consistent view of the currently "in-use" ResourceLocks.
|
||||
+ */
|
||||
+ resourceLock = resourceLocksByPath.get(key);
|
||||
+ if (resourceLock == null) {
|
||||
+ resourceLock = new ResourceLock(key);
|
||||
+ resourceLocksByPath.put(key, resourceLock);
|
||||
+ }
|
||||
+ resourceLock.count.incrementAndGet();
|
||||
+ }
|
||||
+ // Obtain the lock outside the sync as it will block if there is a current write lock.
|
||||
+ resourceLock.reentrantLock.readLock().lock();
|
||||
+ return resourceLock;
|
||||
+ }
|
||||
+ @Override
|
||||
+ public void unlockForRead(ResourceLock resourceLock) {
|
||||
+ // Unlock outside the sync as there is no need to do it inside.
|
||||
+ resourceLock.reentrantLock.readLock().unlock();
|
||||
+ synchronized (resourceLocksByPathLock) {
|
||||
+ /*
|
||||
+ * Decrement the usage count and remove ResourceLocks no longer required inside the sync to ensure that that
|
||||
+ * map always has a consistent view of the currently "in-use" ResourceLocks.
|
||||
+ */
|
||||
+ if (resourceLock.count.decrementAndGet() == 0) {
|
||||
+ resourceLocksByPath.remove(resourceLock.key);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
+ @Override
|
||||
+ public ResourceLock lockForWrite(String path) {
|
||||
+ String key = getLockKey(path);
|
||||
+ ResourceLock resourceLock = null;
|
||||
+ synchronized (resourceLocksByPathLock) {
|
||||
+ /*
|
||||
+ * Obtain the ResourceLock and increment the usage count inside the sync to ensure that that map always has
|
||||
+ * a consistent view of the currently "in-use" ResourceLocks.
|
||||
+ */
|
||||
+ resourceLock = resourceLocksByPath.get(key);
|
||||
+ if (resourceLock == null) {
|
||||
+ resourceLock = new ResourceLock(key);
|
||||
+ resourceLocksByPath.put(key, resourceLock);
|
||||
+ }
|
||||
+ resourceLock.count.incrementAndGet();
|
||||
+ }
|
||||
+ // Obtain the lock outside the sync as it will block if there are any other current locks.
|
||||
+ resourceLock.reentrantLock.writeLock().lock();
|
||||
+ return resourceLock;
|
||||
+ }
|
||||
+ @Override
|
||||
+ public void unlockForWrite(ResourceLock resourceLock) {
|
||||
+ // Unlock outside the sync as there is no need to do it inside.
|
||||
+ resourceLock.reentrantLock.writeLock().unlock();
|
||||
+ synchronized (resourceLocksByPathLock) {
|
||||
+ /*
|
||||
+ * Decrement the usage count and remove ResourceLocks no longer required inside the sync to ensure that that
|
||||
+ * map always has a consistent view of the currently "in-use" ResourceLocks.
|
||||
+ */
|
||||
+ if (resourceLock.count.decrementAndGet() == 0) {
|
||||
+ resourceLocksByPath.remove(resourceLock.key);
|
||||
+ }
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
diff -rupN java/org/apache/catalina/webresources/FileResource.java java/org/apache/catalina/webresources/FileResource.java
|
||||
--- java/org/apache/catalina/webresources/FileResource.java 2021-12-09 13:29:38.000000000 +0200
|
||||
+++ java/org/apache/catalina/webresources/FileResource.java 2025-01-17 14:41:16.585281119 +0200
|
||||
@@ -30,6 +30,8 @@ import java.nio.file.attribute.BasicFile
|
||||
import java.security.cert.Certificate;
|
||||
import java.util.jar.Manifest;
|
||||
|
||||
+import org.apache.catalina.WebResourceLockSet;
|
||||
+import org.apache.catalina.WebResourceLockSet.ResourceLock;
|
||||
import org.apache.catalina.WebResourceRoot;
|
||||
import org.apache.juli.logging.Log;
|
||||
import org.apache.juli.logging.LogFactory;
|
||||
@@ -62,11 +64,20 @@ public class FileResource extends Abstra
|
||||
private final boolean readOnly;
|
||||
private final Manifest manifest;
|
||||
private final boolean needConvert;
|
||||
+ private final WebResourceLockSet lockSet;
|
||||
+ private final String lockKey;
|
||||
|
||||
public FileResource(WebResourceRoot root, String webAppPath,
|
||||
File resource, boolean readOnly, Manifest manifest) {
|
||||
+ this(root, webAppPath, resource, readOnly, manifest, null, null);
|
||||
+ }
|
||||
+
|
||||
+ public FileResource(WebResourceRoot root, String webAppPath, File resource, boolean readOnly, Manifest manifest,
|
||||
+ WebResourceLockSet lockSet, String lockKey) {
|
||||
super(root,webAppPath);
|
||||
this.resource = resource;
|
||||
+ this.lockSet = lockSet;
|
||||
+ this.lockKey = lockKey;
|
||||
|
||||
if (webAppPath.charAt(webAppPath.length() - 1) == '/') {
|
||||
String realName = resource.getName() + '/';
|
||||
@@ -120,7 +131,22 @@ public class FileResource extends Abstra
|
||||
if (readOnly) {
|
||||
return false;
|
||||
}
|
||||
- return resource.delete();
|
||||
+ /*
|
||||
+ * Lock the path for writing until the delete is complete. The lock prevents concurrent reads and writes (e.g.
|
||||
+ * HTTP GET and PUT / DELETE) for the same path causing corruption of the FileResource where some of the fields
|
||||
+ * are set as if the file exists and some as set as if it does not.
|
||||
+ */
|
||||
+ ResourceLock lock = null;
|
||||
+ if (lockSet != null) {
|
||||
+ lock = lockSet.lockForWrite(lockKey);
|
||||
+ }
|
||||
+ try {
|
||||
+ return resource.delete();
|
||||
+ } finally {
|
||||
+ if (lockSet != null) {
|
||||
+ lockSet.unlockForWrite(lock);
|
||||
+ }
|
||||
+ }
|
||||
}
|
||||
|
||||
@Override
|
||||
diff -rupN java/org/apache/catalina/webresources/LocalStrings.properties java/org/apache/catalina/webresources/LocalStrings.properties
|
||||
--- java/org/apache/catalina/webresources/LocalStrings.properties 2021-12-09 13:29:38.000000000 +0200
|
||||
+++ java/org/apache/catalina/webresources/LocalStrings.properties 2025-01-17 14:41:39.210308532 +0200
|
||||
@@ -31,6 +31,7 @@ cachedResource.invalidURL=Unable to crea
|
||||
|
||||
classpathUrlStreamHandler.notFound=Unable to load the resource [{0}] using the thread context class loader or the current class''s class loader
|
||||
|
||||
+dirResourceSet.isCaseSensitive.fail=Error trying to determine if file system at [{0}] is case sensitive so assuming it is not case sensitive
|
||||
dirResourceSet.manifestFail=Failed to read manifest from [{0}]
|
||||
dirResourceSet.notDirectory=The directory specified by base and internal path [{0}]{1}[{2}] does not exist.
|
||||
dirResourceSet.writeNpe=The input stream may not be null
|
||||
@ -58,7 +58,7 @@
|
||||
Name: pki-servlet-engine
|
||||
Epoch: 1
|
||||
Version: %{major_version}.%{minor_version}.%{micro_version}
|
||||
Release: 1%{?dist}
|
||||
Release: 1%{?dist}.2
|
||||
Summary: Apache Servlet/JSP Engine, RI for Servlet %{servletspec}/JSP %{jspspec} API
|
||||
Group: System Environment/Daemons
|
||||
License: ASL 2.0
|
||||
@ -81,6 +81,8 @@ Patch0: tomcat-%{major_version}.%{minor_version}-bootstrap-MANIFEST.MF.pa
|
||||
Patch1: tomcat-%{major_version}.%{minor_version}-tomcat-users-webapp.patch
|
||||
Patch2: tomcat-%{major_version}.%{minor_version}-catalina-policy.patch
|
||||
Patch3: exclude-OSGi-metadata.patch
|
||||
Patch4: rhbz-2314686.patch
|
||||
Patch5: rhbz-2332817.patch
|
||||
|
||||
BuildArch: noarch
|
||||
|
||||
@ -143,6 +145,8 @@ find . -type f \( -name "*.bat" -o -name "*.class" -o -name Thumbs.db -o -name "
|
||||
%patch1 -p0
|
||||
%patch2 -p0
|
||||
%patch3 -p0
|
||||
%patch4 -p0
|
||||
%patch5 -p0
|
||||
|
||||
# Since we don't support ECJ in RHEL anymore, remove the class that requires it
|
||||
%{__rm} -f java/org/apache/jasper/compiler/JDTCompiler.java
|
||||
@ -385,6 +389,14 @@ fi
|
||||
%{_javadir}/tomcat-servlet-%{servletspec}*.jar
|
||||
|
||||
%changelog
|
||||
* Fri Jan 17 2025 Dimitris Soumis <dsoumis@redhat.com> - 1:9.0.50-1.el9_2.2
|
||||
- Resolves: RHEL-71715
|
||||
pki-servlet-engine: RCE due to TOCTOU issue in JSP compilation (CVE-2024-50379)
|
||||
|
||||
* Thu Oct 17 2024 Adam Krajcik <akrajcik@redhat.com> - 1:9.0.50-1.el9_2.1
|
||||
- Resolves: RHEL-60105
|
||||
pki-servlet-engine: Denial of service in tomcat (CVE-2024-38286)
|
||||
|
||||
* Thu Feb 24 2022 Chris Kelley <ckelley@redhat.com> - 1:9.0.50-1
|
||||
- Update to JWS 5.6.1
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user