Skip to content

Fix use-after-free on re-entrant ftp_close() during a transfer#118

Closed
iliaal wants to merge 1 commit into
PHP-8.4from
ftp-reentrant-close-uaf
Closed

Fix use-after-free on re-entrant ftp_close() during a transfer#118
iliaal wants to merge 1 commit into
PHP-8.4from
ftp-reentrant-close-uaf

Conversation

@iliaal

@iliaal iliaal commented Jun 22, 2026

Copy link
Copy Markdown
Owner

ftp_get(), ftp_put(), ftp_append() and the ftp_nb_* variants cache the ftpbuf_t on the C stack and stream the received or sent bytes through a caller-supplied php_stream. When that stream is a user-registered wrapper, its stream_read/stream_write handler can call ftp_close() on the same connection mid-transfer, freeing the ftpbuf_t and databuf_t while the engine still holds them, so the transfer resumes on freed memory. Valgrind confirms invalid reads in the ftp_get() receive loop, freed by the re-entrant ftp_close(). The fix sets an in_use flag around each engine transfer (including ftp_nb_continue_read/ftp_nb_continue_write, which the non-blocking entry points run through) and makes ftp_close() throw while it is set. Smallest trigger: a wrapper whose stream_write calls ftp_close($conn) during ftp_get($conn, 'wrapper://x', ...). Reported privately as GHSA-vr2x-x6ff-4586 and rejected per the project security policy (the trigger is PHP code, not the FTP server), so filing as a normal bug.

A user stream wrapper passed to ftp_get(), ftp_put(), ftp_append() or
the ftp_nb_* variants can call ftp_close() from its stream_read or
stream_write handler while the engine still holds the freed ftpbuf_t and
databuf_t on the C stack, so the transfer resumes on freed memory. Guard
each engine transfer with an in_use flag and make ftp_close() throw while
it is set.

Closes phpGH-22400
@iliaal iliaal force-pushed the ftp-reentrant-close-uaf branch from 7102ae6 to b758b53 Compare June 22, 2026 15:22
@iliaal

iliaal commented Jun 22, 2026

Copy link
Copy Markdown
Owner Author

Superseded by the upstream PR php#22400.

@iliaal iliaal closed this Jun 22, 2026
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