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

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:
Miss Islington (bot) 2025-02-19 14:16:30 +01:00 committed by GitHub
parent 526617ed68
commit 3abcace681
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 31 additions and 1 deletions

View file

@ -52,6 +52,9 @@ AllowedVersions = ('IMAP4REV1', 'IMAP4') # Most recent first
# 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 @@ class IMAP4:
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):