Skip to content

Fix use-after-free when proc_open() pipe is closed from its user filter - #25281

Open
bukka wants to merge 1 commit into
php:PHP-8.4from
bukka:proc_close_in_filter
Open

bukka wants to merge 1 commit into
php:PHP-8.4from
bukka:proc_close_in_filter

Conversation

@bukka

@bukka bukka commented Nov 7, 2026

Copy link
Copy Markdown
Member

The process resource destructor closed every pipe stream with zend_list_close(), regardless of whether a user filter callback was running on it. Both proc_close() and releasing the last reference to the process from inside such a callback freed the pipe stream and the filter under the running callback.

The destructor now only drops its reference to a pipe stream marked PHP_STREAM_FLAG_NO_FCLOSE, so the stream closes with its last reference instead. proc_close() additionally refuses to close the process while one of its pipes carries that flag, since waiting for the child with the pipe still open could deadlock. It warns and returns -1, its documented error value, like pclose() does for such a stream.

Comment thread ext/standard/proc_open.c Resolved
The process resource destructor closed every pipe stream with
zend_list_close(), regardless of whether a user filter callback was
running on it. Both proc_close() and releasing the last reference to the
process from inside such a callback freed the pipe stream and the filter
under the running callback.

The destructor now only drops its reference to a pipe stream marked
PHP_STREAM_FLAG_NO_FCLOSE, so the stream closes with its last reference
instead. It also does not wait for the child in that case, as the child
may be blocked on the kept open pipe, which would deadlock when the
destructor runs nested in another pclose() or proc_close() that still
has FG(pclose_wait) set.

proc_close() additionally refuses to close the process while one of its
pipes carries that flag, since waiting for the child with the pipe still
open could deadlock. It warns and returns -1, its documented error
value, like pclose() does for such a stream.
@bukka
bukka force-pushed the proc_close_in_filter branch from 3c25aa4 to 0f01ffe Compare November 7, 2026 21:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants