libfreerdp-core: add locks to disable full duplex BIOs (currently unsafe)

This commit is contained in:
Marc-André Moreau 2014-05-30 14:53:10 -04:00
parent d2ad5f698b
commit b1416af362
6 changed files with 72 additions and 16 deletions

View File

@ -1601,14 +1601,22 @@ rdpTsg* tsg_new(rdpTransport* transport)
rdpTsg* tsg; rdpTsg* tsg;
tsg = (rdpTsg*) calloc(1, sizeof(rdpTsg)); tsg = (rdpTsg*) calloc(1, sizeof(rdpTsg));
if (!tsg) if (!tsg)
return NULL; return NULL;
tsg->transport = transport; tsg->transport = transport;
tsg->settings = transport->settings; tsg->settings = transport->settings;
tsg->rpc = rpc_new(tsg->transport); tsg->rpc = rpc_new(tsg->transport);
if (!tsg->rpc) if (!tsg->rpc)
goto out_free; goto out_free;
if (!InitializeCriticalSectionAndSpinCount(&(tsg->DuplexLock), 4000))
goto out_free;
tsg->FullDuplex = FALSE;
tsg->PendingPdu = FALSE; tsg->PendingPdu = FALSE;
return tsg; return tsg;
@ -1619,8 +1627,11 @@ out_free:
void tsg_free(rdpTsg* tsg) void tsg_free(rdpTsg* tsg)
{ {
if (tsg != NULL) if (tsg)
{ {
if (!tsg->FullDuplex)
DeleteCriticalSection(&(tsg->DuplexLock));
free(tsg->MachineName); free(tsg->MachineName);
rpc_free(tsg->rpc); rpc_free(tsg->rpc);
free(tsg); free(tsg);

View File

@ -31,6 +31,7 @@ typedef struct rdp_tsg rdpTsg;
#include <winpr/rpc.h> #include <winpr/rpc.h>
#include <winpr/winpr.h> #include <winpr/winpr.h>
#include <winpr/wtypes.h> #include <winpr/wtypes.h>
#include <winpr/synch.h>
#include <winpr/error.h> #include <winpr/error.h>
#include <time.h> #include <time.h>
@ -69,6 +70,8 @@ struct rdp_tsg
rdpTransport* transport; rdpTransport* transport;
CONTEXT_HANDLE TunnelContext; CONTEXT_HANDLE TunnelContext;
CONTEXT_HANDLE ChannelContext; CONTEXT_HANDLE ChannelContext;
CRITICAL_SECTION DuplexLock;
BOOL FullDuplex;
}; };
typedef WCHAR* RESOURCENAME; typedef WCHAR* RESOURCENAME;

View File

@ -74,25 +74,33 @@ long transport_bio_buffered_callback(BIO* bio, int mode, const char* argp, int a
static int transport_bio_buffered_write(BIO* bio, const char* buf, int num) static int transport_bio_buffered_write(BIO* bio, const char* buf, int num)
{ {
int status, ret; int status, ret;
rdpTcp *tcp = (rdpTcp *)bio->ptr; rdpTcp* tcp = (rdpTcp*) bio->ptr;
int nchunks, committedBytes, i; int nchunks, committedBytes, i;
DataChunk chunks[2]; DataChunk chunks[2];
if (!tcp->fullDuplex)
EnterCriticalSection(&(tcp->duplexLock));
ret = num; ret = num;
BIO_clear_flags(bio, (BIO_FLAGS_WRITE | BIO_FLAGS_SHOULD_RETRY | BIO_FLAGS_IO_SPECIAL));
tcp->writeBlocked = FALSE; tcp->writeBlocked = FALSE;
BIO_clear_retry_flags(bio);
/* we directly append extra bytes in the xmit buffer, this could be prevented /* we directly append extra bytes in the xmit buffer, this could be prevented
* but for now it makes the code more simple. * but for now it makes the code more simple.
*/ */
if (buf && num && !ringbuffer_write(&tcp->xmitBuffer, (const BYTE *)buf, num)) if (buf && num && !ringbuffer_write(&tcp->xmitBuffer, (const BYTE*) buf, num))
{ {
fprintf(stderr, "%s: an error occured when writing(toWrite=%d)\n", __FUNCTION__, num); fprintf(stderr, "%s: an error occured when writing(toWrite=%d)\n", __FUNCTION__, num);
if (!tcp->fullDuplex)
LeaveCriticalSection(&(tcp->duplexLock));
return -1; return -1;
} }
committedBytes = 0; committedBytes = 0;
nchunks = ringbuffer_peek(&tcp->xmitBuffer, chunks, ringbuffer_used(&tcp->xmitBuffer)); nchunks = ringbuffer_peek(&tcp->xmitBuffer, chunks, ringbuffer_used(&tcp->xmitBuffer));
for (i = 0; i < nchunks; i++) for (i = 0; i < nchunks; i++)
{ {
while (chunks[i].size) while (chunks[i].size)
@ -123,16 +131,23 @@ static int transport_bio_buffered_write(BIO* bio, const char* buf, int num)
out: out:
ringbuffer_commit_read_bytes(&tcp->xmitBuffer, committedBytes); ringbuffer_commit_read_bytes(&tcp->xmitBuffer, committedBytes);
if (!tcp->fullDuplex)
LeaveCriticalSection(&(tcp->duplexLock));
return ret; return ret;
} }
static int transport_bio_buffered_read(BIO* bio, char* buf, int size) static int transport_bio_buffered_read(BIO* bio, char* buf, int size)
{ {
int status; int status;
rdpTcp *tcp = (rdpTcp *)bio->ptr; rdpTcp* tcp = (rdpTcp*) bio->ptr;
if (!tcp->fullDuplex)
EnterCriticalSection(&(tcp->duplexLock));
tcp->readBlocked = FALSE; tcp->readBlocked = FALSE;
BIO_clear_flags(bio, (BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY | BIO_FLAGS_IO_SPECIAL)); BIO_clear_retry_flags(bio);
status = BIO_read(bio->next_bio, buf, size); status = BIO_read(bio->next_bio, buf, size);
/*fprintf(stderr, "%s: size=%d status=%d shouldRetry=%d\n", __FUNCTION__, size, status, BIO_should_retry(bio->next_bio)); */ /*fprintf(stderr, "%s: size=%d status=%d shouldRetry=%d\n", __FUNCTION__, size, status, BIO_should_retry(bio->next_bio)); */
@ -143,6 +158,9 @@ static int transport_bio_buffered_read(BIO* bio, char* buf, int size)
tcp->readBlocked = TRUE; tcp->readBlocked = TRUE;
} }
if (!tcp->fullDuplex)
LeaveCriticalSection(&(tcp->duplexLock));
return status; return status;
} }
@ -548,6 +566,11 @@ rdpTcp* tcp_new(rdpSettings* settings)
tcp->sockfd = -1; tcp->sockfd = -1;
tcp->settings = settings; tcp->settings = settings;
if (!InitializeCriticalSectionAndSpinCount(&(tcp->duplexLock), 4000))
goto out_ringbuffer;
tcp->fullDuplex = FALSE;
#ifndef _WIN32 #ifndef _WIN32
tcp->event = CreateFileDescriptorEvent(NULL, FALSE, FALSE, tcp->sockfd); tcp->event = CreateFileDescriptorEvent(NULL, FALSE, FALSE, tcp->sockfd);
@ -570,6 +593,9 @@ void tcp_free(rdpTcp* tcp)
if (!tcp) if (!tcp)
return; return;
if (!tcp->fullDuplex)
DeleteCriticalSection(&(tcp->duplexLock));
ringbuffer_destroy(&tcp->xmitBuffer); ringbuffer_destroy(&tcp->xmitBuffer);
CloseHandle(tcp->event); CloseHandle(tcp->event);
free(tcp); free(tcp);

View File

@ -51,12 +51,15 @@ struct rdp_tcp
#ifdef _WIN32 #ifdef _WIN32
WSAEVENT wsa_event; WSAEVENT wsa_event;
#endif #endif
BIO *socketBio; BIO* socketBio;
BIO *bufferedBio; BIO* bufferedBio;
RingBuffer xmitBuffer; RingBuffer xmitBuffer;
BOOL writeBlocked; BOOL writeBlocked;
BOOL readBlocked; BOOL readBlocked;
BOOL fullDuplex;
CRITICAL_SECTION duplexLock;
HANDLE event; HANDLE event;
}; };

View File

@ -133,16 +133,22 @@ static int transport_bio_tsg_write(BIO* bio, const char* buf, int num)
tsg = (rdpTsg*) bio->ptr; tsg = (rdpTsg*) bio->ptr;
BIO_clear_flags(bio, (BIO_FLAGS_WRITE | BIO_FLAGS_SHOULD_RETRY | BIO_FLAGS_IO_SPECIAL)); if (!tsg->FullDuplex)
EnterCriticalSection(&(tsg->DuplexLock));
BIO_clear_retry_flags(bio);
status = tsg_write(tsg, (BYTE*) buf, num); status = tsg_write(tsg, (BYTE*) buf, num);
if (status > 0)
return status;
if (status == 0) if (status == 0)
BIO_set_retry_write(bio); BIO_set_retry_write(bio);
if (!tsg->FullDuplex)
LeaveCriticalSection(&(tsg->DuplexLock));
if (status > 0)
return status;
return -1; return -1;
} }
@ -152,9 +158,13 @@ static int transport_bio_tsg_read(BIO* bio, char* buf, int size)
rdpTsg* tsg; rdpTsg* tsg;
tsg = (rdpTsg*) bio->ptr; tsg = (rdpTsg*) bio->ptr;
if (!tsg->FullDuplex)
EnterCriticalSection(&(tsg->DuplexLock));
status = tsg_read(bio->ptr, (BYTE*) buf, size); status = tsg_read(bio->ptr, (BYTE*) buf, size);
BIO_clear_flags(bio, (BIO_FLAGS_READ | BIO_FLAGS_SHOULD_RETRY | BIO_FLAGS_IO_SPECIAL)); BIO_clear_retry_flags(bio);
if (status == 0) if (status == 0)
{ {
@ -166,6 +176,9 @@ static int transport_bio_tsg_read(BIO* bio, char* buf, int size)
status = 0; status = 0;
} }
if (!tsg->FullDuplex)
LeaveCriticalSection(&(tsg->DuplexLock));
return status >= 0 ? status : -1; return status >= 0 ? status : -1;
} }
@ -713,7 +726,6 @@ int transport_read_layer(rdpTransport* transport, BYTE* data, int bytes)
int read = 0; int read = 0;
int status = -1; int status = -1;
while (read < bytes) while (read < bytes)
{ {
status = BIO_read(transport->frontBio, data + read, bytes - read); status = BIO_read(transport->frontBio, data + read, bytes - read);

View File

@ -386,14 +386,15 @@ int tls_write_all(rdpTls* tls, const BYTE* data, int length)
BIO *bio = tls->bio; BIO *bio = tls->bio;
DataChunk chunks[2]; DataChunk chunks[2];
BIO *bufferedBio = findBufferedBio(bio); BIO* bufferedBio = findBufferedBio(bio);
if (!bufferedBio) if (!bufferedBio)
{ {
fprintf(stderr, "%s: error unable to retrieve the bufferedBio in the BIO chain\n", __FUNCTION__); fprintf(stderr, "%s: error unable to retrieve the bufferedBio in the BIO chain\n", __FUNCTION__);
return -1; return -1;
} }
tcp = (rdpTcp *)bufferedBio->ptr; tcp = (rdpTcp*) bufferedBio->ptr;
do do
{ {