Skip to content

main/streams: Bound user stream wrapper recursion with a depth counter - #23848

Open
iliaal wants to merge 1 commit into
php:PHP-8.4from
iliaal:promote/stream-recursion-depth
Open

iliaal wants to merge 1 commit into
php:PHP-8.4from
iliaal:promote/stream-recursion-depth

Conversation

@iliaal

@iliaal iliaal commented Sep 22, 2026

Copy link
Copy Markdown
Member

The userspace wrapper guard only compared the filename being opened against the currently open one, so a wrapper whose stream_open() opens a different path at every level, an incrementing counter in the URL for instance, recursed until the C stack ran out. A per-request nesting counter shared by user_wrapper_opener() and user_wrapper_opendir() now rejects opens past 64 levels with the existing "infinite recursion prevented" error, and is decremented on every exit including the bailout branch. The counter sits at the end of php_file_globals so the struct keeps its layout for extensions built against the 8.4 header.

The userspace wrapper guard only compared the filename being opened against
the currently open one, so a wrapper whose stream_open() opens a different
path at every level, an incrementing counter in the URL for instance,
recursed without bound and exhausted the C stack. Add a per-request nesting
counter shared by user_wrapper_opener() and user_wrapper_opendir() that
rejects opens past 64 levels with the existing "infinite recursion
prevented" error, decremented on every exit including the bailout branch.
Sibling audit, no other entry point nests user-wrapper opens: stat, unlink,
rename, mkdir, rmdir and the metadata handlers do not recurse through
fopen/opendir.
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.

1 participant