-
-
Couldn't load subscription status.
- Fork 33.2k
gh-115952: Fix potential virtual memory allocation denial of service in the pickle module #119204
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 3 commits
822230d
88f1461
048099b
d9d1d1d
6f6f765
d0e667e
3462d0e
becbd25
b257974
1e487ca
184984d
f0c0728
1f4e2f1
c72d095
e89bfea
a80106c
01bc6b9
20aa1bf
ab58869
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -191,6 +191,11 @@ def __init__(self, value): | |
| __all__.extend([x for x in dir() if re.match("[A-Z][A-Z0-9_]+$", x)]) | ||
|
|
||
|
|
||
| # Data larger that this will be read in chunks, to prevent extreme | ||
| # overallocation. | ||
| SAFE_BUF_SIZE = (1 << 20) | ||
|
|
||
|
|
||
| class _Framer: | ||
|
|
||
| _FRAME_SIZE_MIN = 4 | ||
|
|
@@ -289,7 +294,7 @@ def read(self, n): | |
| "pickle exhausted before end of frame") | ||
| return data | ||
| else: | ||
| return self.file_read(n) | ||
| return self.safe_file_read(n) | ||
|
|
||
| def readline(self): | ||
| if self.current_frame: | ||
|
|
@@ -304,11 +309,23 @@ def readline(self): | |
| else: | ||
| return self.file_readline() | ||
|
|
||
| def safe_file_read(self, size): | ||
|
||
| cursize = min(size, SAFE_BUF_SIZE) | ||
| b = self.file_read(cursize) | ||
| while cursize < size and len(b) == cursize: | ||
| delta = min(cursize, size - cursize) | ||
| b += self.file_read(delta) | ||
gpshead marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| cursize += delta | ||
| return b | ||
|
|
||
| def load_frame(self, frame_size): | ||
| if self.current_frame and self.current_frame.read() != b'': | ||
| raise UnpicklingError( | ||
| "beginning of a new frame before end of current frame") | ||
| self.current_frame = io.BytesIO(self.file_read(frame_size)) | ||
| data = self.safe_file_read(frame_size) | ||
| if len(data) < frame_size: | ||
| raise EOFError | ||
| self.current_frame = io.BytesIO(data) | ||
|
|
||
|
|
||
| # Tools used for pickling. | ||
|
|
@@ -1378,12 +1395,17 @@ def load_binbytes8(self): | |
| dispatch[BINBYTES8[0]] = load_binbytes8 | ||
|
|
||
| def load_bytearray8(self): | ||
| len, = unpack('<Q', self.read(8)) | ||
| if len > maxsize: | ||
| size, = unpack('<Q', self.read(8)) | ||
| if size > maxsize: | ||
| raise UnpicklingError("BYTEARRAY8 exceeds system's maximum size " | ||
| "of %d bytes" % maxsize) | ||
| b = bytearray(len) | ||
| self.readinto(b) | ||
| cursize = min(size, SAFE_BUF_SIZE) | ||
| b = bytearray(cursize) | ||
| if self.readinto(b) == cursize: | ||
| while cursize < size and len(b) == cursize: | ||
| delta = min(cursize, size - cursize) | ||
| b += self.read(delta) | ||
gpshead marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| cursize += delta | ||
| self.append(b) | ||
| dispatch[BYTEARRAY8[0]] = load_bytearray8 | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,3 @@ | ||
| Fix a vulnerability in the :mod:`pickle` module which allowed to consume | ||
|
||
| arbitrary large amount of memory when loading a small data which does not | ||
| even involve arbitrary code execution. | ||
Uh oh!
There was an error while loading. Please reload this page.