[3.9] gh-119511: Fix a potential denial of service in imaplib (GH-119514) (#130248)

The IMAP4 client could consume an arbitrary amount of memory when trying
to connect to a malicious server, because it read a "literal" data with a
single read(size) call, and BufferedReader.read() allocates the bytes
object of the specified size before reading. Now the IMAP4 client reads data
by chunks, therefore the amount of used memory is limited by the
amount of the data actually been sent by the server.
(cherry picked from commit 735f25c5e3)

Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
Co-authored-by: Gregory P. Smith <greg@krypto.org>
This commit is contained in:
Hugo van Kemenade 2025-02-19 15:31:01 +02:00 committed by GitHub
parent d80cbdd708
commit f116a9c15c
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 32 additions and 1 deletions

View file

@ -52,6 +52,9 @@
# search command can be quite large, so we now use 1M.
_MAXLINE = 1000000
# Data larger than this will be read in chunks, to prevent extreme
# overallocation.
_SAFE_BUF_SIZE = 1 << 20
# Commands
@ -315,7 +318,13 @@ def open(self, host='', port=IMAP4_PORT, timeout=None):
def read(self, size):
"""Read 'size' bytes from remote."""
return self.file.read(size)
cursize = min(size, _SAFE_BUF_SIZE)
data = self.file.read(cursize)
while cursize < size and len(data) == cursize:
delta = min(cursize, size - cursize)
data += self.file.read(delta)
cursize += delta
return data
def readline(self):