From 3fce288c6624383d58ccf82bfb38e4beb262a333 Mon Sep 17 00:00:00 2001 From: Hardening Date: Thu, 10 Jul 2014 23:35:11 +0200 Subject: [PATCH] Fix unclean SSL disconnection This patch prevent an infinite loop when the remote peer disconnect the socket without cleanly closing the SSL connection. --- libfreerdp/core/tcp.c | 32 ++++++++++++++++++-------------- libfreerdp/crypto/tls.c | 3 ++- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/libfreerdp/core/tcp.c b/libfreerdp/core/tcp.c index 245d3b1b9..314704928 100644 --- a/libfreerdp/core/tcp.c +++ b/libfreerdp/core/tcp.c @@ -122,23 +122,28 @@ static int transport_bio_simple_read(BIO* bio, char* buf, int size) BIO_clear_flags(bio, BIO_FLAGS_READ); status = _recv((SOCKET) bio->num, buf, size, 0); + if (status > 0) + return status; - if (status <= 0) + if (status == 0) { - error = WSAGetLastError(); - - if ((error == WSAEWOULDBLOCK) || (error == WSAEINTR) || - (error == WSAEINPROGRESS) || (error == WSAEALREADY)) - { - BIO_set_flags(bio, (BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY)); - } - else - { - BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY); - } + BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY); + return 0; } - return status; + error = WSAGetLastError(); + + if ((error == WSAEWOULDBLOCK) || (error == WSAEINTR) || + (error == WSAEINPROGRESS) || (error == WSAEALREADY)) + { + BIO_set_flags(bio, (BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY)); + } + else + { + BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY); + } + + return -1; } static int transport_bio_simple_puts(BIO* bio, const char* str) @@ -327,7 +332,6 @@ static int transport_bio_buffered_read(BIO* bio, char* buf, int size) if (!BIO_should_retry(bio->next_bio)) { BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY); - status = -1; goto out; } diff --git a/libfreerdp/crypto/tls.c b/libfreerdp/crypto/tls.c index 9075f1e59..da0a0cc93 100644 --- a/libfreerdp/crypto/tls.c +++ b/libfreerdp/crypto/tls.c @@ -152,7 +152,8 @@ static int bio_rdp_tls_read(BIO* bio, char* buf, int size) break; case SSL_ERROR_SYSCALL: - status = 0; + BIO_clear_flags(bio, BIO_FLAGS_SHOULD_RETRY); + status = -1; break; } }