Page MenuHomePhabricator

ssh_disconnect does not properly reset the pending_call_state to SSH_PENDING_CALL_NONE
Open, Needs TriagePublic

Description

Calling ssh_disconnect on a session while it is pending on the completion of a non-blocking connection leaves the session in a non-reusable, invalid state. If ssh_disconnect is called before setting the pending_call_state to SSH_PENDING_CALL_NONE (client.c:632), which typically happens when client code detects a connection timeout condition on an asynchronous / non-blocking session and aborts the connection, pending_call_state remains equal to SSH_PENDING_CALL_CONNECT. As a result, next attempt at calling ssh_connect will skip initialization of session_state to SSH_SESSION_STATE_CONNECTING (client.c:567) due to the earlier jump to pending (client.c:527), which will prevent proper detection of the condition leading to returning SSH_AGAIN (client.c:629) and result in returning SSH_ERROR (client.c:636) instead.

A solution would be to reset pending_call_state to SSH_PENDING_CALL_NONE in ssh_disconnect, possibly just after setting the session_state to SSH_SESSION_STATE_DISCONNECTED (client.c:724)

}
session->opts.fd = SSH_INVALID_SOCKET;
session->session_state=SSH_SESSION_STATE_DISCONNECTED;

+ session->pending_call_state=SSH_PENDING_CALL_NONE;

while ((it=ssh_list_get_iterator(session->channels)) != NULL) {
  ssh_channel_do_free(ssh_iterator_value(ssh_channel,it));

Event Timeline

fgariepy created this task.Sat, Sep 26, 6:39 PM
Jakuje added a project: Restricted Project.Fri, Oct 2, 12:42 PM
Jakuje added a subscriber: Jakuje.

Thank you for the report and analysis. It looks reasonable to add this reset to disconnect function, rather than keeping it in invalid state. I submitted the following merge request for review:

https://gitlab.com/libssh/libssh-mirror/-/merge_requests/141