Page MenuHomePhabricator

sftp_free() segfaults when called after ssh_disconnect()
Closed, ResolvedPublic

Description

When ssh_disconnect() is called before sftp_free(), the sftp_free() call segfaults.

#include <libssh/libssh.h>
#include <libssh/sftp.h>
#include <stdio.h>

int main(void) {
        ssh_session session = ssh_new();
        ssh_options_set(session, SSH_OPTIONS_HOST, "localhost");
        ssh_connect(session);

        if (ssh_userauth_publickey_auto(session, NULL, NULL) != SSH_AUTH_SUCCESS) {
                fprintf(stderr, "Public key auth failed.\n");
                return -1;
        }

        sftp_session sftp = sftp_new(session);
        sftp_init(sftp);

        ssh_disconnect(session);
        sftp_free(sftp);

        ssh_free(session);
        return 0;
}

The backtrace is

#0  0x00007f5bcae5206e in ssh_buffer_allocate_size (buffer=buffer@entry=0x0, len=len@entry=5) at /usr/src/debug/libssh-0.8.7-1.fc29.x86_64/src/buffer.c:340
#1  0x00007f5bcae52d14 in ssh_buffer_pack_allocate_va (ap=0x7ffe281b6880, argc=2, format=0x7f5bcae89a6e "bd", buffer=0x0)
    at /usr/src/debug/libssh-0.8.7-1.fc29.x86_64/src/buffer.c:902
#2  _ssh_buffer_pack (buffer=0x0, format=format@entry=0x7f5bcae89a6e "bd", argc=argc@entry=2) at /usr/src/debug/libssh-0.8.7-1.fc29.x86_64/src/buffer.c:1060
#3  0x00007f5bcae558c2 in ssh_channel_send_eof (channel=0x1837c60) at /usr/src/debug/libssh-0.8.7-1.fc29.x86_64/src/channels.c:1113
#4  0x00007f5bcae7df1d in sftp_free (sftp=0x1837c10) at /usr/src/debug/libssh-0.8.7-1.fc29.x86_64/src/sftp.c:315
#5  0x000000000040125c in main ()

I understand that keeping the order neat is suggested but it might be hard in some environments, for example using libssh from dynamic languages where the user might want to explicitly disconnect() early, and will do so before the object holding the sftp_session pointer gets destroyed.

Possible (untested) patch might be

diff --git a/src/channels.c b/src/channels.c
index d339f732..86230729 100644
--- a/src/channels.c
+++ b/src/channels.c
@@ -1114,6 +1114,9 @@ int ssh_channel_send_eof(ssh_channel channel)
     }
 
     session = channel->session;
+    if (session == NULL || session->out_buffer == NULL) {
+        return rc;
+    }
 
     err = ssh_buffer_pack(session->out_buffer,
                           "bd",

This is on Fedora 29 with libssh-0.8.7-1.fc29.x86_64.