Skip to content

fix: avoid use-after-free when re-entering ostream_redirect - #6205

Open
sayed0200 wants to merge 1 commit into
pybind:masterfrom
sayed0200:iostream-redirect-reentry-uaf
Open

sayed0200 wants to merge 1 commit into
pybind:masterfrom
sayed0200:iostream-redirect-reentry-uaf

Conversation

@sayed0200

Copy link
Copy Markdown

Description

detail::OstreamRedirect::enter() runs redirect_stdout.reset(new scoped_ostream_redirect()). Calling __enter__ a second time without an __exit__ in between (nesting the same ostream_redirect context manager) constructs the replacement before reset() destroys the current one, so the new scoped_ostream_redirect records std::cout.rdbuf() while that still points at the buffer owned by the redirect reset() is about to delete. After the delete the live redirect holds a dangling old streambuf, and on __exit__ its destructor restores std::cout/std::cerr to that freed buffer. The next write to the stream dereferences freed memory.

Minimal repro, stdout only:

r = m.ostream_redirect(stdout=True, stderr=False)
r.__enter__()
r.__enter__()
r.__exit__()
m.raw_output("boom")  # use-after-free, segfaults

Releasing the existing redirect before constructing the replacement makes the new one capture the real original buffer, so no dangling pointer is left behind. Single enter/exit and sequential reuse of the same object are unaffected.

The added test_redirect_reentry segfaults on the current headers and passes with the fix.

This fix was found and prepared with AI assistance and reviewed by me before submitting.

Suggested changelog entry:

  • Fixed a use-after-free in py::add_ostream_redirect when the context manager's __enter__ was entered again without an intervening __exit__.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant