libfreerdp-core: add locks to disable full duplex BIOs (currently unsafe)
This commit is contained in:
parent
d2ad5f698b
commit
b1416af362
@ -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);
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
@ -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
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user