From: Stefan Eissing Date: Sun, 8 Jun 2025 10:00:00 +0000 (+0200) Subject: pingpong: on disconnect, check for unflushed pingpong state X-Git-Tag: curl-8_15_0~315 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c314759c4c40114a510f2d67de2d51edc6eec16c;p=thirdparty%2Fcurl.git pingpong: on disconnect, check for unflushed pingpong state When a pingpong based protocol tries to perform a connection disconnect, it sends a sort of "logout" command to the server, unless the connection is deemed dead. But the disconnect might happen before pingpong data has been completely sent, in which case sending the "logout" will not work. Check the pingpong state and do not "logout" when data is pending. This was detected as a condition in fuzzing that triggered a debug assert in the pingpong sending. Closes #17555 --- diff --git a/lib/ftp.c b/lib/ftp.c index 2c6138e980..3dd7fed045 100644 --- a/lib/ftp.c +++ b/lib/ftp.c @@ -4117,7 +4117,7 @@ static CURLcode ftp_disconnect(struct Curl_easy *data, will try to send the QUIT command, otherwise it will just return. */ ftpc->shutdown = TRUE; - if(dead_connection) + if(dead_connection || Curl_pp_needs_flush(data, &ftpc->pp)) ftpc->ctl_valid = FALSE; /* The FTP session may or may not have been allocated/setup at this point! */ diff --git a/lib/imap.c b/lib/imap.c index fc38a5b61e..fa17b77151 100644 --- a/lib/imap.c +++ b/lib/imap.c @@ -1780,12 +1780,11 @@ static CURLcode imap_disconnect(struct Curl_easy *data, (void)data; if(imapc) { /* We cannot send quit unconditionally. If this connection is stale or - bad in any way, sending quit and waiting around here will make the + bad in any way (pingpong has pending data to send), + sending quit and waiting around here will make the disconnect wait in vain and cause more problems than we need to. */ - - /* The IMAP session may or may not have been allocated/setup at this - point! */ - if(!dead_connection && conn->bits.protoconnstart) { + if(!dead_connection && conn->bits.protoconnstart && + !Curl_pp_needs_flush(data, &imapc->pp)) { if(!imap_perform_logout(data, imapc)) (void)imap_block_statemach(data, imapc, TRUE); /* ignore errors */ } diff --git a/lib/pop3.c b/lib/pop3.c index aa8c2d834a..3e3070e333 100644 --- a/lib/pop3.c +++ b/lib/pop3.c @@ -1450,7 +1450,8 @@ static CURLcode pop3_disconnect(struct Curl_easy *data, bad in any way, sending quit and waiting around here will make the disconnect wait in vain and cause more problems than we need to. */ - if(!dead_connection && conn->bits.protoconnstart) { + if(!dead_connection && conn->bits.protoconnstart && + !Curl_pp_needs_flush(data, &pop3c->pp)) { if(!pop3_perform_quit(data, conn)) (void)pop3_block_statemach(data, conn, TRUE); /* ignore errors on QUIT */ } diff --git a/lib/smtp.c b/lib/smtp.c index d39bb58d5d..99a348e234 100644 --- a/lib/smtp.c +++ b/lib/smtp.c @@ -1625,7 +1625,8 @@ static CURLcode smtp_disconnect(struct Curl_easy *data, bad in any way, sending quit and waiting around here will make the disconnect wait in vain and cause more problems than we need to. */ - if(!dead_connection && conn->bits.protoconnstart) { + if(!dead_connection && conn->bits.protoconnstart && + !Curl_pp_needs_flush(data, &smtpc->pp)) { if(!smtp_perform_quit(data, smtpc)) (void)smtp_block_statemach(data, smtpc, TRUE); /* ignore on QUIT */ }