90ce6a
diff -up ./java/org/apache/catalina/websocket/LocalStrings.properties.orig ./java/org/apache/catalina/websocket/LocalStrings.properties
90ce6a
--- ./java/org/apache/catalina/websocket/LocalStrings.properties.orig	2020-07-17 15:26:30.639711576 -0400
90ce6a
+++ ./java/org/apache/catalina/websocket/LocalStrings.properties	2020-07-17 15:26:39.051723026 -0400
90ce6a
@@ -14,6 +14,7 @@
90ce6a
 # limitations under the License.
90ce6a
 
90ce6a
 frame.eos=The end of the stream was reached before the expected number of payload bytes could be read
90ce6a
+frame.invalidLength=An invalid payload length was specified
90ce6a
 frame.invalidUtf8=A sequence of bytes was received that did not represent valid UTF-8
90ce6a
 frame.readFailed=Failed to read the first byte of the next WebSocket frame. The return value from the read was [{0}]
90ce6a
 frame.readEos=The end of the stream was reached when trying to read the first byte of a new WebSocket frame
90ce6a
diff -up ./java/org/apache/catalina/websocket/WsFrame.java.orig ./java/org/apache/catalina/websocket/WsFrame.java
90ce6a
--- ./java/org/apache/catalina/websocket/WsFrame.java.orig	2020-07-17 15:26:44.341730227 -0400
90ce6a
+++ ./java/org/apache/catalina/websocket/WsFrame.java	2020-07-17 15:27:02.712755233 -0400
90ce6a
@@ -84,6 +84,12 @@ public class WsFrame {
90ce6a
             blockingRead(processor, extended);
90ce6a
             payloadLength = Conversions.byteArrayToLong(extended);
90ce6a
         }
90ce6a
+        // The most significant bit of those 8 bytes is required to be zero
90ce6a
+        // (see RFC 6455, section 5.2). If the most significant bit is set,
90ce6a
+        // the resulting payload length will be negative so test for that.
90ce6a
+        if (payloadLength < 0) {
90ce6a
+            throw new IOException(sm.getString("frame.invalidLength"));
90ce6a
+        }
90ce6a
 
90ce6a
         if (isControl()) {
90ce6a
             if (payloadLength > 125) {
90ce6a
diff -up ./java/org/apache/tomcat/websocket/LocalStrings.properties.orig ./java/org/apache/tomcat/websocket/LocalStrings.properties
90ce6a
--- ./java/org/apache/tomcat/websocket/LocalStrings.properties.orig	2020-07-17 15:25:18.940613973 -0400
90ce6a
+++ ./java/org/apache/tomcat/websocket/LocalStrings.properties	2020-07-17 15:25:24.954622163 -0400
90ce6a
@@ -63,6 +63,7 @@ wsFrame.noContinuation=A new message was
90ce6a
 wsFrame.notMasked=The client frame was not masked but all client frames must be masked
90ce6a
 wsFrame.oneByteCloseCode=The client sent a close frame with a single byte payload which is not valid
90ce6a
 wsFrame.partialHeaderComplete=WebSocket frame received. fin [{0}], rsv [{1}], OpCode [{2}], payload length [{3}]
90ce6a
+wsFrame.payloadMsbInvalid=An invalid WebSocket frame was received - the most significant bit of a 64-bit payload was illegally set
90ce6a
 wsFrame.sessionClosed=The client data cannot be processed because the session has already been closed
90ce6a
 wsFrame.textMessageTooBig=The decoded text message was too big for the output buffer and the endpoint does not support partial messages
90ce6a
 wsFrame.wrongRsv=The client frame set the reserved bits to [{0}] for a message with opCode [{1}] which was not supported by this endpoint
90ce6a
diff -up ./java/org/apache/tomcat/websocket/WsFrameBase.java.orig ./java/org/apache/tomcat/websocket/WsFrameBase.java
90ce6a
--- ./java/org/apache/tomcat/websocket/WsFrameBase.java.orig	2020-07-17 15:25:04.371594139 -0400
90ce6a
+++ ./java/org/apache/tomcat/websocket/WsFrameBase.java	2020-07-17 15:25:14.292607645 -0400
90ce6a
@@ -260,6 +260,13 @@ public abstract class WsFrameBase {
90ce6a
             readPos += 2;
90ce6a
         } else if (payloadLength == 127) {
90ce6a
             payloadLength = byteArrayToLong(inputBuffer, readPos, 8);
90ce6a
+            // The most significant bit of those 8 bytes is required to be zero
90ce6a
+            // (see RFC 6455, section 5.2). If the most significant bit is set,
90ce6a
+            // the resulting payload length will be negative so test for that.
90ce6a
+            if (payloadLength < 0) {
90ce6a
+                throw new WsIOException(
90ce6a
+                        new CloseReason(CloseCodes.PROTOCOL_ERROR, sm.getString("wsFrame.payloadMsbInvalid")));
90ce6a
+            }
90ce6a
             readPos += 8;
90ce6a
         }
90ce6a
         if (Util.isControl(opCode)) {
90ce6a
diff -up ./webapps/docs/changelog.xml.orig ./webapps/docs/changelog.xml
90ce6a
--- ./webapps/docs/changelog.xml.orig	2020-07-20 10:35:46.126504549 -0400
90ce6a
+++ ./webapps/docs/changelog.xml	2020-07-20 10:36:48.577591763 -0400
90ce6a
@@ -57,6 +57,16 @@
90ce6a
   They eventually become mixed with the numbered issues. (I.e., numbered
90ce6a
   issues do not "pop up" wrt. others).
90ce6a
 -->
90ce6a
+<section name="Tomcat 7.0.76-15 (csutherl)">
90ce6a
+  <subsection name="WebSocket">
90ce6a
+    <changelog>
90ce6a
+      <fix>
90ce6a
+        <bug>64563</bug>: Add additional validation of payload length for
90ce6a
+        WebSocket messages. (markt)
90ce6a
+      </fix>
90ce6a
+    </changelog>
90ce6a
+  </subsection>
90ce6a
+</section>
90ce6a
 <section name="Tomcat 7.0.76-14 (csutherl)">
90ce6a
   <subsection name="Catalina">
90ce6a
     <changelog>