Skip to content

libssh2: Connection is not closed with CURLOPT_TIMEOUT #6990

@ccbenny

Description

@ccbenny

This setup:

  • We are using libcurl in our in-house software.
  • The code uses SFTP with libssh2 via the curl_easy interface.
  • We are setting the transfer timeout using CURLOPT_TIMEOUT.

Problem:
We observe a serious memory leak. I have tracked it down to libssh2_session_free never being called.

  • Our code calls curl_easy_cleanup.
  • We get to the code in libssh2.c:ssh_statemach_act that handles SSH_SFTP_SHUTDOWN.
  • This calls libssh2_sftp_shutdown and that gives EWOULDBLOCK.
  • The backtrace here is:
#1  0x00007ffff7f76cc1 in ssh_block_statemach (data=0x5555555a60c8, conn=0x5555555bca08, 
    duringconnect=false) at vssh/libssh2.c:2954
#2  0x00007ffff7f77a4c in sftp_disconnect (data=0x5555555a60c8, conn=0x5555555bca08, 
    dead_connection=false) at vssh/libssh2.c:3473
#3  0x00007ffff7f54724 in Curl_disconnect (data=0x5555555a60c8, conn=0x5555555bca08, 
    dead_connection=false) at url.c:855
#4  0x00007ffff7ede9d5 in Curl_conncache_close_all_connections (connc=0x5555555babf8)
    at conncache.c:556
#5  0x00007ffff7f269e2 in curl_multi_cleanup (multi=0x5555555baaf8) at multi.c:2596
#6  0x00007ffff7f53172 in Curl_close (datap=0x7fffffffde28) at url.c:380
#7  0x00007ffff7ef08d3 in curl_easy_cleanup (data=0x0) at easy.c:742
#8  0x0000555555555ef2 in sftp_upload (url=0x7fffffffe5ba "sftp://benny@localhost:1122/tmp/testing", 
    private_key=0x7fffffffe5ec "/home/benny/Projects/cds_c/src/libs/libmecomcurl/testsrc/sshd/clientkey.rsa", request=0x7ffff79935f0 <__GI__IO_fread>, request_size=0, request_userp=0x55555559ed20)
    at sftpcurl.c:159
#9  0x0000555555555ff1 in test_curl (url=0x7fffffffe5ba "sftp://benny@localhost:1122/tmp/testing", 
    requestFileName=0x7fffffffe5e2 "/dev/null", 
    key=0x7fffffffe5ec "/home/benny/Projects/cds_c/src/libs/libmecomcurl/testsrc/sshd/clientkey.rsa", 
    debug=0) at tSftp.c:58
#10 0x00005555555560a8 in test_curl_memory_leak (count=12, 
    url=0x7fffffffe5ba "sftp://benny@localhost:1122/tmp/testing", 
--Type <RET> for more, q to quit, c to continue without paging--c
    ull", key=0x7fffffffe5ec "/home/benny/Projects/cds_c/src/libs/libmecomcurl/testsrc/sshd/clientkey.rsa") at tSftp.c:83
#11 0x00005555555562db in main (argc=6, argv=0x7fffffffe2a8) at tSftp.c:149
  • I.e. ssh_statemach_act is called from ssh_block_statemach.
  • In ssh_block_statemach the reaction to this is that connect.c:Curl_timeleft gets called.
  • Curl_timeleft fails (returns a negative number), because data->set.timeout is set to a timeout, but data->progress.t_startop is 0.
  • After that ssh_block_statemach returns and all the data allocated by libssh2 is abandoned.

It seems that the CURL handle that is used in Curl_conncache_close_all_connections is not the same as the one used during the SFTP data transfer. This code probably does not expect that there is more network traffic during the disconnect handler that would need timeout handling. It is not quite clear where the correct value for data->progress.t_startop would come from. sftp_disconnect could of course just set it to the current time, but that might not be entirely correct.

A couple of additional thoughts:

  • Even if the timeout issue were real, the resources allocated by libssh2 should still be freed.
  • The debug function that we set with CURLOPT_DEBUGFUNCTION in the top-level handle is not set in the second CURL handle. This means that the call to failf in ssh_block_statemach does not show up anywhere.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions