Skip to content
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

[security] list_resize(): integer overflow if newsize is too large #97616

Closed
vstinner opened this issue Sep 28, 2022 · 4 comments
Closed

[security] list_resize(): integer overflow if newsize is too large #97616

vstinner opened this issue Sep 28, 2022 · 4 comments
Labels
type-bug An unexpected behavior, bug, or error type-security A security issue

Comments

@vstinner
Copy link
Member

vstinner commented Sep 28, 2022

Jordan Limor reported an issue in the C list_resize() function called when a Python list is resized:

When list_resize is hit with the maximum value for a c_ssize_t, the
overallocation strategy causes an overflow in the total allocated bytes.
This results in a call to PyMem_Realloc where the argument is 0 (and one
byte is allocated), but the resulting list's size is set to PY_SSIZE_T_MAX.

Example bug.py:

import sys
import faulthandler; faulthandler.enable()

x=[0]*65
del x[1:]
assert len(x) == 1

print("resize list", flush=True)
max_size = ((2 ** (tuple.__itemsize__ * 8) - 1) // 2)
x *= max_size
print(f"{len(x)=}")
print(f"{sys.getsizeof(x)=}")

# crash on reading uninitizalized memory
print("x[8]=", end="", flush=True)
print(x[8])

Output:

$ python3.10 bug.py 
resize list
Fatal Python error: Segmentation fault

Current thread 0x00007fe16ead0740 (most recent call first):
  File "bug.py", line 10 in <module>
Erreur de segmentation (core dumped)
@vstinner vstinner added type-bug An unexpected behavior, bug, or error type-security A security issue labels Sep 28, 2022
@vstinner vstinner changed the title list_resize(): integer overflow if newsize is too large [security] list_resize(): integer overflow if newsize is too large Sep 28, 2022
@vstinner
Copy link
Member Author

When the bug triggers, list_resize() is called with newsize=9223372036854775807: 2**63-1 (PY_SSIZE_T_MAX).

new_allocated = ((size_t)newsize + (newsize >> 3) + 6) & ~(size_t)3; gives 10376293541461622788.

But (newsize - Py_SIZE(self) > (Py_ssize_t)(new_allocated - newsize)) condition is true, and so new_allocated = ((size_t)newsize + 3) & ~(size_t)3; is computed which gives new_allocated=9223372036854775808 which is PY_SSIZE_T_MAX + 1.

The integer overflow occurs on num_allocated_bytes = new_allocated * sizeof(PyObject *); which gives: num_allocated_bytes=0.

miss-islington pushed a commit to miss-islington/cpython that referenced this issue Sep 28, 2022
…7617)

Fix multiplying a list by an integer (list *= int): detect the
integer overflow when the new allocated length is close to the
maximum size.  Issue reported by Jordan Limor.

list_resize() now checks for integer overflow before multiplying the
new allocated length by the list item size (sizeof(PyObject*)).
(cherry picked from commit a5f092f)

Co-authored-by: Victor Stinner <[email protected]>
miss-islington pushed a commit to miss-islington/cpython that referenced this issue Sep 28, 2022
…7617)

Fix multiplying a list by an integer (list *= int): detect the
integer overflow when the new allocated length is close to the
maximum size.  Issue reported by Jordan Limor.

list_resize() now checks for integer overflow before multiplying the
new allocated length by the list item size (sizeof(PyObject*)).
(cherry picked from commit a5f092f)

Co-authored-by: Victor Stinner <[email protected]>
miss-islington pushed a commit to miss-islington/cpython that referenced this issue Sep 28, 2022
…7617)

Fix multiplying a list by an integer (list *= int): detect the
integer overflow when the new allocated length is close to the
maximum size.  Issue reported by Jordan Limor.

list_resize() now checks for integer overflow before multiplying the
new allocated length by the list item size (sizeof(PyObject*)).
(cherry picked from commit a5f092f)

Co-authored-by: Victor Stinner <[email protected]>
miss-islington pushed a commit to miss-islington/cpython that referenced this issue Sep 28, 2022
…7617)

Fix multiplying a list by an integer (list *= int): detect the
integer overflow when the new allocated length is close to the
maximum size.  Issue reported by Jordan Limor.

list_resize() now checks for integer overflow before multiplying the
new allocated length by the list item size (sizeof(PyObject*)).
(cherry picked from commit a5f092f)

Co-authored-by: Victor Stinner <[email protected]>
miss-islington pushed a commit to miss-islington/cpython that referenced this issue Sep 28, 2022
…7617)

Fix multiplying a list by an integer (list *= int): detect the
integer overflow when the new allocated length is close to the
maximum size.  Issue reported by Jordan Limor.

list_resize() now checks for integer overflow before multiplying the
new allocated length by the list item size (sizeof(PyObject*)).
(cherry picked from commit a5f092f)

Co-authored-by: Victor Stinner <[email protected]>
vstinner added a commit that referenced this issue Sep 28, 2022
Fix multiplying a list by an integer (list *= int): detect the
integer overflow when the new allocated length is close to the
maximum size.  Issue reported by Jordan Limor.

list_resize() now checks for integer overflow before multiplying the
new allocated length by the list item size (sizeof(PyObject*)).
miss-islington added a commit that referenced this issue Sep 28, 2022
Fix multiplying a list by an integer (list *= int): detect the
integer overflow when the new allocated length is close to the
maximum size.  Issue reported by Jordan Limor.

list_resize() now checks for integer overflow before multiplying the
new allocated length by the list item size (sizeof(PyObject*)).
(cherry picked from commit a5f092f)

Co-authored-by: Victor Stinner <[email protected]>
miss-islington added a commit that referenced this issue Sep 28, 2022
Fix multiplying a list by an integer (list *= int): detect the
integer overflow when the new allocated length is close to the
maximum size.  Issue reported by Jordan Limor.

list_resize() now checks for integer overflow before multiplying the
new allocated length by the list item size (sizeof(PyObject*)).
(cherry picked from commit a5f092f)

Co-authored-by: Victor Stinner <[email protected]>
ambv pushed a commit that referenced this issue Oct 4, 2022
…H-97627)

gh-97616: list_resize() checks for integer overflow (GH-97617)

Fix multiplying a list by an integer (list *= int): detect the
integer overflow when the new allocated length is close to the
maximum size.  Issue reported by Jordan Limor.

list_resize() now checks for integer overflow before multiplying the
new allocated length by the list item size (sizeof(PyObject*)).
(cherry picked from commit a5f092f)

Co-authored-by: Victor Stinner <[email protected]>
ambv pushed a commit that referenced this issue Oct 4, 2022
…H-97628)

gh-97616: list_resize() checks for integer overflow (GH-97617)

Fix multiplying a list by an integer (list *= int): detect the
integer overflow when the new allocated length is close to the
maximum size.  Issue reported by Jordan Limor.

list_resize() now checks for integer overflow before multiplying the
new allocated length by the list item size (sizeof(PyObject*)).
(cherry picked from commit a5f092f)

Co-authored-by: Victor Stinner <[email protected]>
ambv pushed a commit that referenced this issue Oct 5, 2022
…97629)

Fix multiplying a list by an integer (list *= int): detect the
integer overflow when the new allocated length is close to the
maximum size.  Issue reported by Jordan Limor.

list_resize() now checks for integer overflow before multiplying the
new allocated length by the list item size (sizeof(PyObject*)).
(cherry picked from commit a5f092f)

Co-authored-by: Victor Stinner <[email protected]>
@gpshead
Copy link
Member

gpshead commented Oct 22, 2022

The PRs were merged, I believe this is complete.

@gpshead gpshead closed this as completed Oct 22, 2022
pablogsal pushed a commit that referenced this issue Oct 24, 2022
Fix multiplying a list by an integer (list *= int): detect the
integer overflow when the new allocated length is close to the
maximum size.  Issue reported by Jordan Limor.

list_resize() now checks for integer overflow before multiplying the
new allocated length by the list item size (sizeof(PyObject*)).
(cherry picked from commit a5f092f)

Co-authored-by: Victor Stinner <[email protected]>
pablogsal pushed a commit that referenced this issue Oct 24, 2022
Fix multiplying a list by an integer (list *= int): detect the
integer overflow when the new allocated length is close to the
maximum size.  Issue reported by Jordan Limor.

list_resize() now checks for integer overflow before multiplying the
new allocated length by the list item size (sizeof(PyObject*)).
(cherry picked from commit a5f092f)

Co-authored-by: Victor Stinner <[email protected]>
@mattip
Copy link
Contributor

mattip commented Oct 28, 2022

In the test, isn't the calculation max_size = ((2 ** (tuple.__itemsize__ * 8) - 1) // 2) always going to yield sys.maxsize? It seems so on linux64, linux32, win64. I ask because PyPy has no tuple.__itemsize__ and it seems this is an implementation detail.

mozillazg pushed a commit to mozillazg/pypy that referenced this issue Oct 28, 2022
@python python deleted a comment Nov 2, 2022
@vstinner
Copy link
Member Author

vstinner commented Nov 3, 2022

In the test, isn't the calculation max_size = ((2 ** (tuple.itemsize * 8) - 1) // 2) always going to yield sys.maxsize?

I wrote the test based on the code that we received to trigger the crash. I wrote PR #99057 to fix the case, is it better for PyPy?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
type-bug An unexpected behavior, bug, or error type-security A security issue
Projects
None yet
Development

No branches or pull requests

3 participants