Skip to content

gh-60198: Prevent memoryview pointing to freed heap memory #105290

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

Open
wants to merge 11 commits into
base: main
Choose a base branch
from

Conversation

furkanonder
Copy link
Contributor

@furkanonder furkanonder commented Jun 4, 2023

@furkanonder furkanonder marked this pull request as ready for review July 23, 2023 07:51
@gpshead gpshead added type-security A security issue type-crash A hard crash of the interpreter, possibly with a core dump type-bug An unexpected behavior, bug, or error and removed type-security A security issue labels Jul 30, 2023
@gpshead gpshead self-assigned this Jul 30, 2023
@AA-Turner AA-Turner changed the title GH-60198: Prevent memoryview points to freed heap memory GH-60198: Prevent memoryview pointing to freed heap memory Jul 30, 2023
Comment on lines +1563 to +1571
PyObject *exc = PyErr_GetRaisedException();
release_res = PyObject_CallMethod(memobj, "release", NULL);
_PyErr_ChainExceptions1(exc);
Py_DECREF(memobj);
if (release_res == NULL) {
Py_XDECREF(res);
return -1;
}
Py_DECREF(release_res);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes sense to me. The performance impact should be minimal as it's only a cleanup method call after the buffer's been entirely read.

However, since mv.release() can potentially raise, this is a change in behavior so we have to decide whether the risk of existing code breakage is worth backporting the patch to older releases.

I see @gpshead decided this isn't a security issue so we won't be bringing it to 3.8, 3.9, 3.10. Question is if we want it in 3.11 and 3.12.

@furkanonder furkanonder changed the title GH-60198: Prevent memoryview pointing to freed heap memory gh-60198: Prevent memoryview pointing to freed heap memory Aug 6, 2023
@oconnor663
Copy link
Contributor

oconnor663 commented Sep 1, 2023

Edit: Ah, my comment below is just an example of point number 1 here: #60198 (comment)

I'm not very familiar with the Python C APIs, so I might be mistaken, but I don't think this change is enough to categorically prevent use-after-free here. This PR is releasing the memoryview that was given to the caller as an argument to readinto, and that does prevent the caller from corrupting memory by holding on to that view, but it doesn't prevent the caller from creating additional views that the BufferedReader doesn't know about before the first one is released. I can recreate the segfault like this:

diff --git a/Lib/test/test_memoryview.py b/Lib/test/test_memoryview.py
index 0eac7bc06a..922104d55c 100644
--- a/Lib/test/test_memoryview.py
+++ b/Lib/test/test_memoryview.py
@@ -660,13 +660,13 @@ def __bool__(self):
     def test_gh60198(self):
         global view
 
         class File(io.RawIOBase):
             def readinto(self, buf):
                 global view
-                view = buf
+                view = memoryview(buf)
 
             def readable(self):
                 return True
 
         f = io.BufferedReader(File())
         # get view of buffer used by BufferedReader
$ make test TESTOPTS="-v test_memoryview"
...
test_gh60198 (test.test_memoryview.OtherTest.test_gh60198) ... Fatal Python error: Segmentation fault

Current thread 0x00007fc1b0b1e740 (most recent call first):
  File "/home/joconnor/cpython/Lib/test/test_memoryview.py", line 682 in test_gh60198
  File "/home/joconnor/cpython/Lib/unittest/case.py", line 589 in _callTestMethod
  File "/home/joconnor/cpython/Lib/unittest/case.py", line 634 in run
  File "/home/joconnor/cpython/Lib/unittest/case.py", line 690 in __call__
  File "/home/joconnor/cpython/Lib/unittest/suite.py", line 122 in run
  File "/home/joconnor/cpython/Lib/unittest/suite.py", line 84 in __call__
  File "/home/joconnor/cpython/Lib/unittest/suite.py", line 122 in run
  File "/home/joconnor/cpython/Lib/unittest/suite.py", line 84 in __call__
  File "/home/joconnor/cpython/Lib/unittest/suite.py", line 122 in run
  File "/home/joconnor/cpython/Lib/unittest/suite.py", line 84 in __call__
  File "/home/joconnor/cpython/Lib/unittest/runner.py", line 240 in run
  File "/home/joconnor/cpython/Lib/test/support/__init__.py", line 1115 in _run_suite
  File "/home/joconnor/cpython/Lib/test/support/__init__.py", line 1241 in run_unittest
  File "/home/joconnor/cpython/Lib/test/libregrtest/runtest.py", line 294 in _test_module
  File "/home/joconnor/cpython/Lib/test/libregrtest/runtest.py", line 330 in _runtest_inner2
  File "/home/joconnor/cpython/Lib/test/libregrtest/runtest.py", line 373 in _runtest_inner
  File "/home/joconnor/cpython/Lib/test/libregrtest/runtest.py", line 248 in _runtest
  File "/home/joconnor/cpython/Lib/test/libregrtest/runtest.py", line 278 in runtest
  File "/home/joconnor/cpython/Lib/test/libregrtest/main.py", line 365 in rerun_failed_tests
  File "/home/joconnor/cpython/Lib/test/libregrtest/main.py", line 803 in _main
  File "/home/joconnor/cpython/Lib/test/libregrtest/main.py", line 758 in main
  File "/home/joconnor/cpython/Lib/test/libregrtest/main.py", line 822 in main
  File "/home/joconnor/cpython/Lib/test/__main__.py", line 2 in <module>
  File "<frozen runpy>", line 88 in _run_code
  File "<frozen runpy>", line 198 in _run_module_as_main

Extension modules: _testcapi (total: 1)
make: *** [Makefile:1983: test] Segmentation fault (core dumped)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
awaiting review type-bug An unexpected behavior, bug, or error type-crash A hard crash of the interpreter, possibly with a core dump
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants