Repository navigation
Conversation
ftp_nb_get() sets ftp->nb = 1 only on success, but its bail: path left the
flag set. Whether that path is taken is decided by the server: the guard at
the top of the function aborts a pending transfer and then requires response
226 or 250.
After such a bail, PHP_FUNCTION(ftp_nb_get) has already set ftp->stream to
NULL and closed the stream it opened, while ftp->closestream stays true.
ftp_nb_continue() then passed its !ftp->nb gate, reached
if (ret != PHP_FTP_MOREDATA && ftp->closestream) {
php_stream_close(ftp->stream);
and dereferenced the cleared pointer.
ftp_nb_continue_read()'s own bail: already clears the flag; this makes
ftp_nb_get() consistent with it.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
ftp_nb_get()setsftp->nb = 1only on success, but itsbail:path left the flag set.Whether that path is taken is decided by the server: the guard at the top of the function
aborts a pending transfer and then requires response 226 or 250.
After such a bail,
PHP_FUNCTION(ftp_nb_get)has already setftp->streamto NULL and closedthe stream it opened, while
ftp->closestreamstays true.ftp_nb_continue()then passes its!ftp->nbgate and reachesdereferencing the cleared pointer.
ftp_nb_continue_read()'s ownbail:already clears the flag; this makesftp_nb_get()consistent with it.
Crash
On a stripped build it faults earlier, in
ftp_nb_continue_read()ondata->fd(
mov 0x4(%r12),%esiwithr12 == 0;offsetof(databuf_t, fd)is 4). Adding a NULL checkthere alone only moves the crash to
php_ftp.c:863- I tried that first and it still exited139 - so the flag is the right place to fix it.
Test
ext/ftp/tests/ftp_nb_get_rejected_abort.phpt, with aserver.inccase that answers theaborted transfer with 451. Without the change the test process dies at the
ftp_nb_continue()call; with it the call reports there is nothing to continue. Full
ext/ftpsuite: 62 passed,0 failed, 4 skipped.
Note
php_ftp.c:862could also take theftp->stream &&test thatftp.c:167already uses, andon this path the first transfer's stream is dropped without being closed. I left both alone to
keep the change minimal; happy to add either.
🤖 Generated with Claude Code