Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
SUSE:SLE-12-SP4:GA
python-Twisted.34938
CVE-2024-41671.patch
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File CVE-2024-41671.patch of Package python-Twisted.34938
Index: Twisted-15.2.1/twisted/web/http.py =================================================================== --- Twisted-15.2.1.orig/twisted/web/http.py +++ Twisted-15.2.1/twisted/web/http.py @@ -1584,6 +1584,9 @@ class _ChunkedTransferDecoder(object): self.finishCallback = finishCallback self._buffer = bytearray() self._start = 0 + self._trailerHeaders = [] + self._maxTrailerHeadersSize = 2**16 + self._receivedTrailerHeadersSize = 0 def _dataReceived_CHUNK_LENGTH(self): @@ -1656,6 +1659,42 @@ class _ChunkedTransferDecoder(object): self.finishCallback(data) return False + eolIndex = self._buffer.find(b"\r\n", self._start) + + if eolIndex == -1: + # Still no end of network line marker found. + # + # Check if we've run up against the trailer size limit: if the next + # read contains the terminating CRLF then we'll have this many bytes + # of trailers (including the CRLFs). + minTrailerSize = ( + self._receivedTrailerHeadersSize + + len(self._buffer) + + (1 if self._buffer.endswith(b"\r") else 2) + ) + if minTrailerSize > self._maxTrailerHeadersSize: + raise _MalformedChunkedDataError("Trailer headers data is too long.") + # Continue processing more data. + return False + + if eolIndex > 0: + # A trailer header was detected. + self._trailerHeaders.append(self._buffer[0:eolIndex]) + del self._buffer[0 : eolIndex + 2] + self._start = 0 + self._receivedTrailerHeadersSize += eolIndex + 2 + if self._receivedTrailerHeadersSize > self._maxTrailerHeadersSize: + raise _MalformedChunkedDataError("Trailer headers data is too long.") + return True + + # eolIndex in this part of code is equal to 0 + + data = memoryview(self._buffer)[2:].tobytes() + + del self._buffer[:] + self.state = "FINISHED" + self.finishCallback(data) + return False def _dataReceived_BODY(self): if len(self._buffer) >= self.length: @@ -1809,8 +1848,8 @@ class HTTPChannel(basic.LineReceiver, po def _finishRequestBody(self, data): - self.allContentReceived() self.setLineMode(data) + self.allContentReceived() def _maybeChooseTransferDecoder(self, header, data): """ @@ -1826,6 +1865,8 @@ class HTTPChannel(basic.LineReceiver, po # Can this header determine the length? if header == b'content-length': + if not data.isdigit(): + return fail() try: length = int(data) except ValueError: @@ -1874,7 +1915,7 @@ class HTTPChannel(basic.LineReceiver, po header, data = line.split(b':', 1) header = header.lower() - data = data.strip() + data = data.strip(b" \t") if not self._maybeChooseTransferDecoder(header,data): return False Index: Twisted-15.2.1/twisted/web/test/test_http.py =================================================================== --- Twisted-15.2.1.orig/twisted/web/test/test_http.py +++ Twisted-15.2.1/twisted/web/test/test_http.py @@ -2606,3 +2606,83 @@ class HexHelperTests(unittest.Synchronou for s in self.badStrings: self.assertRaises(ValueError, http._hexint, s) + +class PipeliningBodyTests(unittest.TestCase, ResponseTestMixin): + """ + Pipelined requests get buffered and executed in the order received, + not processed in parallel. + """ + + requests = ( + b"POST / HTTP/1.1\r\n" + b"Content-Length: 10\r\n" + b"\r\n" + b"0123456789" + # Chunk encoded request. + b"POST / HTTP/1.1\r\n" + b"Transfer-Encoding: chunked\r\n" + b"\r\n" + b"a\r\n" + b"0123456789\r\n" + b"0\r\n" + b"\r\n" + ) + + expectedResponses = [ + ( + b"HTTP/1.1 200 OK", + b"Request: /", + b"Command: POST", + b"Version: HTTP/1.1", + b"Content-Length: 21", + b"'''\n10\n0123456789'''\n", + ), + ( + b"HTTP/1.1 200 OK", + b"Request: /", + b"Command: POST", + b"Version: HTTP/1.1", + b"Content-Length: 23", + b"'''\nNone\n0123456789'''\n", + ), + ] + + def test_immediateTinyTube(self): + """ + Imitate a slow connection that delivers one byte at a time. + + (L{DummyHTTPHandler}) immediately responds, but no more + than one + """ + b = StringTransport() + a = http.HTTPChannel() + a.requestFactory = DummyHTTPHandler + a.makeConnection(b) + + # one byte at a time, to stress it. + for byte in iterbytes(self.requests): + a.dataReceived(byte) + # There is never more than one request dispatched at a time: + self.assertLessEqual(len(a.requests), 1) + + self.assertResponseEquals(b.value(), self.expectedResponses) + + def test_immediateDumpTruck(self): + """ + Imitate a fast connection where several pipelined + requests arrive in a single read. The request handler + (L{DummyHTTPHandler}) immediately responds. + + This doesn't check the at-most-one pending request + invariant but exercises otherwise uncovered code paths. + See GHSA-c8m8-j448-xjx7. + """ + b = StringTransport() + a = http.HTTPChannel() + a.requestFactory = DummyHTTPHandler + a.makeConnection(b) + + # All bytes at once to ensure there's stuff to buffer. + a.dataReceived(self.requests) + + self.assertResponseEquals(b.value(), self.expectedResponses)
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor