GeezerVisonThe World Wide Web, restored to 800 pixels of glory. | |||||||||||||||||||||
| Home|About|Gaming cabinet|Archives|How it works|Starter sites | |||||||||||||||||||||
GeezerVison is showing github.com — gh-157364: Fix use-after-free in TextIOWrapper during reentrant detach by ashm-dev · Pull Request #157370 · python/cpython Conversation
|
|
I will need a couple more days to look at this, it seems like this is more invasive than necessary to me and makes a number of not needed for the core UAF bug report. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
|
For gh-157364 I think the bug, and solution, is actually in Buffered I/O. This PR changes Text I/O to keep one more reference, which may also be needed. The issue though is that Buffered I/O has an internal allocation which it passes as an argument to the Raw I/O That makes two pieces to fix here:
|
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Thanks for looking into this, @cmaloney! Regarding point 1: passing mbuf->master = *info; mbuf->master.obj = NULL; Because of this, the resulting Regarding point 2: CPython method calls via |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
|
For 1: The |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
@cmaloney Gentle ping — could you please check if the updated `memoryview` approach in 9763043 looks good to you? @vstinner All CI checks are passing and the review comments have been addressed. Ready for merge whenever you have a moment. Thanks! |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
I don't understand well how _bufferedreader_raw_read_getbuffer() works. How is it different from the current PyBuffer_FillInfo() + PyMemoryView_FromBuffer() code? |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
The key difference is reference ownership:
We can't use standard |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
|
I have been triaging some old I/O bugs and came across gh-60198 which is exactly the BufferedReader memoryview bug here. That could be pulled out as a separate smaller PR that is likely quicker to land with its own NEWS. I think this should have two news entries: one the io.TexTIOWrapper keeping a reference to I don't like adding the two new members to In the TextIO the Incref and decref living in very different functions I'm not a big fan of... I would much rather keep |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
@vstinner @cmaloney I narrowed this PR to the TextIOWrapper fix for gh-157364. I removed the BufferedReader change and added the requested check that the wrapper is detached after |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
Just a general remark: you're making many large changes on this PR. It's not easy to follow these changes. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
Good: the test does crash without the fix. So it confirms that the test checks the modified C code.
$ ./python -m test -v test_io.test_textio -m test_reentrant_detach_during_read
(...)Warning -- Unraisable exception
Exception ignored while finalizing file <_io.BufferedReader>:
Traceback (most recent call last):
File "/home/vstinner/python/main/Lib/test/test_io/test_textio.py", line 1651, in readinto
wrapper.detach()
~~~~~~~~~~~~~~^^
RuntimeError: reentrant call inside <_io.BufferedReader>
Fatal Python error: Segmentation fault
<Cannot show all threads while the GIL is disabled>
Stack (most recent call first):
File "/home/vstinner/python/main/Lib/test/test_io/test_textio.py", line 1661 in test_reentrant_detach_during_read
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Returning a strong reference in buffer_access_safe() sounds like a safe move. I checked that buffer_access_safe() callers do Py_DECREF() on the buffer.
./python -m test -R 3:3 test_io doesn't report leaks. But it reports negative reference count which is surprising:
$ ./python -m test -R 3:3 test_io.test_textio
(...)
test_io.test_textio leaked [-1, -1, -1] references, sum=-3 (this is fine)
$ ./python -m test -R 3:3 test_io.test_bufferedio
(...)
test_io.test_bufferedio leaked [-3, -3, -3] references, sum=-9 (this is fine)
Sorry, something went wrong.
There was an error while loading. Please reload this page.
Ah, I get the same result on the main branch. So it's not caused by this change. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Thanks the updates. I enabled auto-merge, please don't touch the PR (your branch) anymore. This change is a bugfix which should be backported to 3.14 and 3.15 branches. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
CI failed on test_profiling which looks independent, re-running. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
There was an error while loading. Please reload this page.
|
Sorry, @ashm-dev and @vstinner, I could not cleanly backport this to Please backport manually with cherry_picker, see the devguide for more information. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Sorry, @ashm-dev and @vstinner, I could not cleanly backport this to Please backport manually with cherry_picker, see the devguide for more information. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Aha, more conflicts. I will backport the change to 3.14 and 3.15 once the 3.15 branch will be unblocked (next week). |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
PR merged, thanks @ashm-dev for your fix. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Backporting this change is non trivial. I have to backport at least these commits
There are some minor conflicts, and then test_io.textio fails. I will retry next week. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
|
Ok, I found the right order and the correct commits to backport: I created #159591 for the 3.15 branch. |
Sorry, something went wrong.
There was an error while loading. Please reload this page.
…rant detach (#159591) * gh-143008: Fix Null pointer dereferences in TextIOWrapper underlying stream access (#145957) TextIOWrapper keeps its underlying stream in a member called `self->buffer`. That stream can be detached by user code, such as custom `.flush` implementations resulting in `self->buffer` being set to NULL. The implementation often checked at the start of functions if `self->buffer` is in a good state, but did not always recheck after other Python code was called which could modify `self->buffer`. The cases which need to be re-checked are hard to spot so rather than rely on reviewer effort create better safety by making all self->buffer access go through helper functions. Thank you yihong0618 for the test, NEWS and initial implementation in gh-143041. Co-authored-by: yihong0618 <[email protected]> Co-authored-by: Victor Stinner <[email protected]> (cherry picked from commit db4b194) * gh-154523: Fix data-race in `TextIOWrapper.detach()` (#154565) (cherry picked from commit 8440a6a) * gh-157364: Fix use-after-free in io.TextIOWrapper during reentrant detach (#157370) Co-authored-by: Victor Stinner <[email protected]> (cherry picked from commit e19dc47) --------- Co-authored-by: Cody Maloney <[email protected]> Co-authored-by: yihong0618 <[email protected]> Co-authored-by: Brij Kapadia <[email protected]> Co-authored-by: Shamil <[email protected]>
…rant detach (#159600) [3.15] gh-157364: Fix use-after-free in io.TextIOWrapper during reentrant detach (#159591) * gh-143008: Fix Null pointer dereferences in TextIOWrapper underlying stream access (#145957) TextIOWrapper keeps its underlying stream in a member called `self->buffer`. That stream can be detached by user code, such as custom `.flush` implementations resulting in `self->buffer` being set to NULL. The implementation often checked at the start of functions if `self->buffer` is in a good state, but did not always recheck after other Python code was called which could modify `self->buffer`. The cases which need to be re-checked are hard to spot so rather than rely on reviewer effort create better safety by making all self->buffer access go through helper functions. Thank you yihong0618 for the test, NEWS and initial implementation in gh-143041. (cherry picked from commit db4b194) * gh-154523: Fix data-race in `TextIOWrapper.detach()` (#154565) (cherry picked from commit 8440a6a) * gh-157364: Fix use-after-free in io.TextIOWrapper during reentrant detach (#157370) (cherry picked from commit e19dc47) --------- (cherry picked from commit ea1312b) Co-authored-by: Cody Maloney <[email protected]> Co-authored-by: yihong0618 <[email protected]> Co-authored-by: Brij Kapadia <[email protected]> Co-authored-by: Shamil <[email protected]>
There was an error while loading. Please reload this page.
Successfully merging this pull request may close these issues.
There was an error while loading. Please reload this page.