Hacktoberfest 2026: le issue che i maintainer hanno segnato per ottobre, aperte e adatte ai principianti. Sfoglia le issue Hacktoberfest

Leaking LIBSSH2_SESSION objects

Aperta
#220 10 commenti 0 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
5/5
Tempo stimato
Più di una settimana
Idoneità per principianti
35/100
Tipo di issue
Bug
Chiarezza
Abbastanza chiara
Stato di attività
Ferma
Stack tecnologico
rust
Ambito
networking

Direzione di ricerca

Inizia dall’implementazione di Drop per SessionInner e traccia le relative chiamate a libssh2_session_free nelle modalità bloccante e non bloccante. Confronta le astrazioni di trasporto disponibili, incluso il percorso Windows, e determina come completare la pulizia senza una doppia ownership dello stream o un drop che si blocchi indefinitamente. Il lavoro è completato quando le risorse della sessione vengono rilasciate in sicurezza su tutte le piattaforme e modalità supportate.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

I'm using ssh2-rs in an async project (via async-ssh2), and I have stumbled across a problem with the way sessions are freed.

The Drop impl for SessionInner just calls libssh2_session_free and disregards the return value. This is a problem in both blocking and nonblocking modes:

  • In non-blocking mode, libssh2_session_free is likely to return LIBSSH2_ERROR_EAGAIN and need to be called again when the socket is ready
  • In blocking mode, if the caller has set a timeout then it may return LIBSSH2_ERROR_TIMEOUT (and in fact if the caller has not set a timeout, it may hang indefinitely if there is a network problem).

In both cases, if you don't repeatedly call it until you get a 0 returned, then the resources are not released.

In my experience so far, in case of network disturbance it can be pretty difficult to get libsshb2 to properly release the session. The only thing that has worked for me so far is this:

impl Drop for SessionInner {
    fn drop(&mut self) {
        self.set_blocking(true);
        loop {
            let rc = unsafe { raw::libssh2_session_free(self.raw) };
            if rc == 0 {
                break;
            } else {
                // Timeout - drop the transport,
                // which will hopefully cause the socket to close so we can try again
                if let Some(tcp) = self.tcp.take() {
                    let tcp = unsafe { std::net::TcpStream::from_raw_fd(tcp.as_raw_fd()) };
                    let _ = tcp.shutdown(std::net::Shutdown::Both);
                }
            }
        }
    }
}

So, if there is a timeout when calling libssh2_session_free, we shut down the socket and try again. The next time around libssh2 realizes the socket is shut down and finishes the cleanup.

This biggest problem with this is that since tcp is Box<dyn AsRawFd>, we can't call shutdown on it directly, all we can do is get the FD from it, and then create a new TcpStream around it - which is not sound, because then there are two TcpStreams with the same FD. In my testing this has not caused an issue yet, but the documentation explicitly states not to do that. Also, theoretically the the FD might be associated with some other stream type that implements AsRawFd, (eg. UnixStream).

The above is also not good from an async point of view, because the drop fn blocks the thread for potentially a long time. To make it work better in an async context some more work could be required, but that probably should be for another issue.

Finally - whatever approach is used here needs to be replicated for Windows also.

I'm happy to make a PR, if someone can suggest how to avoid the unsoundness described above.

Lingua principale
Rust
Stelle
571
Fork
166
Merge medio
1g 18h
PR unite (30g)
5

Preparare l'ambiente

Questo progetto non fornisce container di sviluppo, Dockerfile né guida per i contributori, quindi l'ambiente è a tuo carico: parti dal suo README e consulta la nostra guida al primo contributo per i passaggi generali.

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di rust-lang/ssh2-rs

Tutte le issue di rust-lang/ssh2-rs

Issue simili

Altre issue su Rust

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.