Merge pull request #4214 from hardening/serial_fixes

Serial fixes
This commit is contained in:
Martin Fleisz 2017-11-08 13:04:04 +01:00 committed by GitHub
commit bd218470fd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 68 additions and 36 deletions

View File

@ -124,20 +124,27 @@ static UINT32 _GetLastErrorToIoStatus(SERIAL_DEVICE* serial)
return STATUS_UNSUCCESSFUL;
}
static void serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp)
static UINT serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp)
{
DWORD DesiredAccess;
DWORD SharedAccess;
DWORD CreateDisposition;
UINT32 PathLength;
if (Stream_GetRemainingLength(irp->input) < 32)
return ERROR_INVALID_DATA;
Stream_Read_UINT32(irp->input, DesiredAccess); /* DesiredAccess (4 bytes) */
Stream_Seek_UINT64(irp->input); /* AllocationSize (8 bytes) */
Stream_Seek_UINT32(irp->input); /* FileAttributes (4 bytes) */
Stream_Read_UINT32(irp->input, SharedAccess); /* SharedAccess (4 bytes) */
Stream_Read_UINT32(irp->input,
CreateDisposition); /* CreateDisposition (4 bytes) */
Stream_Read_UINT32(irp->input, CreateDisposition); /* CreateDisposition (4 bytes) */
Stream_Seek_UINT32(irp->input); /* CreateOptions (4 bytes) */
Stream_Read_UINT32(irp->input, PathLength); /* PathLength (4 bytes) */
if (Stream_GetRemainingLength(irp->input) < PathLength)
return ERROR_INVALID_DATA;
Stream_Seek(irp->input, PathLength); /* Path (variable) */
assert(PathLength == 0); /* MS-RDPESP 2.2.2.2 */
#ifndef _WIN32
@ -191,18 +198,21 @@ static void serial_process_irp_create(SERIAL_DEVICE* serial, IRP* irp)
/* dcb.fBinary = TRUE; */
/* SetCommState(serial->hComm, &dcb); */
assert(irp->FileId == 0);
irp->FileId =
irp->devman->id_sequence++; /* FIXME: why not ((WINPR_COMM*)hComm)->fd? */
irp->FileId = irp->devman->id_sequence++; /* FIXME: why not ((WINPR_COMM*)hComm)->fd? */
irp->IoStatus = STATUS_SUCCESS;
WLog_Print(serial->log, WLOG_DEBUG, "%s (DeviceId: %"PRIu32", FileId: %"PRIu32") created.",
serial->device.name, irp->device->id, irp->FileId);
error_handle:
Stream_Write_UINT32(irp->output, irp->FileId); /* FileId (4 bytes) */
Stream_Write_UINT8(irp->output, 0); /* Information (1 byte) */
return CHANNEL_RC_OK;
}
static void serial_process_irp_close(SERIAL_DEVICE* serial, IRP* irp)
static UINT serial_process_irp_close(SERIAL_DEVICE* serial, IRP* irp)
{
if (Stream_GetRemainingLength(irp->input) < 32)
return ERROR_INVALID_DATA;
Stream_Seek(irp->input, 32); /* Padding (32 bytes) */
if (!CloseHandle(serial->hComm))
@ -219,6 +229,7 @@ static void serial_process_irp_close(SERIAL_DEVICE* serial, IRP* irp)
irp->IoStatus = STATUS_SUCCESS;
error_handle:
Stream_Zero(irp->output, 5); /* Padding (5 bytes) */
return CHANNEL_RC_OK;
}
/**
@ -232,11 +243,15 @@ static UINT serial_process_irp_read(SERIAL_DEVICE* serial, IRP* irp)
UINT64 Offset;
BYTE* buffer = NULL;
DWORD nbRead = 0;
if (Stream_GetRemainingLength(irp->input) < 32)
return ERROR_INVALID_DATA;
Stream_Read_UINT32(irp->input, Length); /* Length (4 bytes) */
Stream_Read_UINT64(irp->input, Offset); /* Offset (8 bytes) */
Stream_Seek(irp->input, 20); /* Padding (20 bytes) */
buffer = (BYTE*)calloc(Length, sizeof(BYTE));
buffer = (BYTE*)calloc(Length, sizeof(BYTE));
if (buffer == NULL)
{
irp->IoStatus = STATUS_NO_MEMORY;
@ -283,11 +298,15 @@ error_handle:
return CHANNEL_RC_OK;
}
static void serial_process_irp_write(SERIAL_DEVICE* serial, IRP* irp)
static UINT serial_process_irp_write(SERIAL_DEVICE* serial, IRP* irp)
{
UINT32 Length;
UINT64 Offset;
DWORD nbWritten = 0;
if (Stream_GetRemainingLength(irp->input) < 32)
return ERROR_INVALID_DATA;
Stream_Read_UINT32(irp->input, Length); /* Length (4 bytes) */
Stream_Read_UINT64(irp->input, Offset); /* Offset (8 bytes) */
Stream_Seek(irp->input, 20); /* Padding (20 bytes) */
@ -318,6 +337,8 @@ static void serial_process_irp_write(SERIAL_DEVICE* serial, IRP* irp)
serial->device.name);
Stream_Write_UINT32(irp->output, nbWritten); /* Length (4 bytes) */
Stream_Write_UINT8(irp->output, 0); /* Padding (1 byte) */
return CHANNEL_RC_OK;
}
@ -334,14 +355,20 @@ static UINT serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp)
UINT32 OutputBufferLength;
BYTE* OutputBuffer = NULL;
DWORD BytesReturned = 0;
Stream_Read_UINT32(irp->input,
OutputBufferLength); /* OutputBufferLength (4 bytes) */
Stream_Read_UINT32(irp->input,
InputBufferLength); /* InputBufferLength (4 bytes) */
if (Stream_GetRemainingLength(irp->input) < 32)
return ERROR_INVALID_DATA;
Stream_Read_UINT32(irp->input, OutputBufferLength); /* OutputBufferLength (4 bytes) */
Stream_Read_UINT32(irp->input, InputBufferLength); /* InputBufferLength (4 bytes) */
Stream_Read_UINT32(irp->input, IoControlCode); /* IoControlCode (4 bytes) */
Stream_Seek(irp->input, 20); /* Padding (20 bytes) */
OutputBuffer = (BYTE*)calloc(OutputBufferLength, sizeof(BYTE));
if (Stream_GetRemainingLength(irp->input) < InputBufferLength)
return ERROR_INVALID_DATA;
OutputBuffer = (BYTE*)calloc(OutputBufferLength, sizeof(BYTE));
if (OutputBuffer == NULL)
{
irp->IoStatus = STATUS_NO_MEMORY;
@ -349,7 +376,6 @@ static UINT serial_process_irp_device_control(SERIAL_DEVICE* serial, IRP* irp)
}
InputBuffer = (BYTE*)calloc(InputBufferLength, sizeof(BYTE));
if (InputBuffer == NULL)
{
irp->IoStatus = STATUS_NO_MEMORY;
@ -381,8 +407,7 @@ error_handle:
* BytesReturned == OutputBufferLength when
* CommDeviceIoControl returns FALSE */
assert(OutputBufferLength == BytesReturned);
Stream_Write_UINT32(irp->output,
BytesReturned); /* OutputBufferLength (4 bytes) */
Stream_Write_UINT32(irp->output, BytesReturned); /* OutputBufferLength (4 bytes) */
if (BytesReturned > 0)
{
@ -425,11 +450,11 @@ static UINT serial_process_irp(SERIAL_DEVICE* serial, IRP* irp)
switch (irp->MajorFunction)
{
case IRP_MJ_CREATE:
serial_process_irp_create(serial, irp);
error = serial_process_irp_create(serial, irp);
break;
case IRP_MJ_CLOSE:
serial_process_irp_close(serial, irp);
error = serial_process_irp_close(serial, irp);
break;
case IRP_MJ_READ:
@ -439,7 +464,7 @@ static UINT serial_process_irp(SERIAL_DEVICE* serial, IRP* irp)
break;
case IRP_MJ_WRITE:
serial_process_irp_write(serial, irp);
error = serial_process_irp_write(serial, irp);
break;
case IRP_MJ_DEVICE_CONTROL:

View File

@ -1797,7 +1797,7 @@ static IUDEVICE* udev_init(UDEVICE* pdev, UINT16 bus_number, UINT16 dev_number)
/* get the first interface and first altsetting */
interface_temp = config_temp->interface[0].altsetting[0];
WLog_DBG(TAG,"Regist Device: Vid: 0x%04"PRIX16" Pid: 0x%04"PRIX16""
WLog_DBG(TAG,"Registered Device: Vid: 0x%04"PRIX16" Pid: 0x%04"PRIX16""
" InterfaceClass = 0x%02"PRIX8"",
pdev->devDescriptor->idVendor,
pdev->devDescriptor->idProduct,

View File

@ -471,7 +471,7 @@ static UINT urbdrc_exchange_capabilities(URBDRC_CHANNEL_CALLBACK* callback, char
break;
default:
WLog_ERR(TAG, "unknown FunctionId 0x%"PRIX32"", FunctionId);
WLog_ERR(TAG, "%s: unknown FunctionId 0x%"PRIX32"", __FUNCTION__, FunctionId);
error = ERROR_NOT_FOUND;
break;
}
@ -1184,7 +1184,7 @@ static UINT urbdrc_process_channel_notification(URBDRC_CHANNEL_CALLBACK* callbac
break;
default:
WLog_VRB(TAG, "unknown FunctionId 0x%"PRIX32"", FunctionId);
WLog_VRB(TAG, "%s: unknown FunctionId 0x%"PRIX32"", __FUNCTION__, FunctionId);
error = 1;
break;
}

View File

@ -425,10 +425,8 @@ BOOL GetCommState(HANDLE hFile, LPDCB lpDCB)
lpLocalDcb->fDtrControl = DTR_CONTROL_DISABLE;
}
lpLocalDcb->fDsrSensitivity = (handflow.ControlHandShake &
SERIAL_DSR_SENSITIVITY) != 0;
lpLocalDcb->fTXContinueOnXoff = (handflow.FlowReplace & SERIAL_XOFF_CONTINUE) !=
0;
lpLocalDcb->fDsrSensitivity = (handflow.ControlHandShake & SERIAL_DSR_SENSITIVITY) != 0;
lpLocalDcb->fTXContinueOnXoff = (handflow.FlowReplace & SERIAL_XOFF_CONTINUE) != 0;
lpLocalDcb->fOutX = (handflow.FlowReplace & SERIAL_AUTO_TRANSMIT) != 0;
lpLocalDcb->fInX = (handflow.FlowReplace & SERIAL_AUTO_RECEIVE) != 0;
lpLocalDcb->fErrorChar = (handflow.FlowReplace & SERIAL_ERROR_CHAR) != 0;

View File

@ -69,6 +69,7 @@ struct winpr_comm
ULONG WaitEventMask;
ULONG PendingEvents;
char eventChar;
/* NB: CloseHandle() has to free resources */
};

View File

@ -146,7 +146,7 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
*
* ReadIntervalTimeout | ReadTotalTimeoutMultiplier | ReadTotalTimeoutConstant | VMIN | VTIME | TMAX |
* 0 | 0 | 0 | N | 0 | INDEF | Blocks for N bytes available.
* 0< Ti <MAXULONG | 0 | 0 | N | Ti | INDEF | Blocks on first byte, then use Ti between bytes.
* 0< Ti <MAXULONG | 0 | 0 | N | Ti | INDEF | Blocks on first byte, then use Ti between bytes.
* MAXULONG | 0 | 0 | 0 | 0 | 0 | Returns immediately with bytes available (don't block)
* MAXULONG | MAXULONG | 0< Tc <MAXULONG | N | 0 | Tc | Blocks on first byte during Tc or returns immediately whith bytes available
* MAXULONG | m | MAXULONG | | Invalid
@ -349,6 +349,14 @@ BOOL CommReadFile(HANDLE hDevice, LPVOID lpBuffer, DWORD nNumberOfBytesToRead,
}
*lpNumberOfBytesRead = nbRead;
EnterCriticalSection(&pComm->EventsLock);
if (pComm->PendingEvents & SERIAL_EV_FREERDP_WAITING)
{
if (pComm->eventChar != '\0' && memchr(lpBuffer, pComm->eventChar, nbRead))
pComm->PendingEvents |= SERIAL_EV_RXCHAR;
}
LeaveCriticalSection(&pComm->EventsLock);
goto return_true;
}
@ -546,13 +554,15 @@ BOOL CommWriteFile(HANDLE hDevice, LPCVOID lpBuffer,
* printer. Its driver was expecting the modem line status
* SERIAL_MSR_DSR true after the sending which was never
* happenning otherwise. A purge was also done before each
* Write operation. The serial port was oppened with:
* Write operation. The serial port was opened with:
* DesiredAccess=0x0012019F. The printer worked fine with
* mstsc. */
tcdrain(pComm->fd_write);
return_true:
LeaveCriticalSection(&pComm->WriteLock);
return TRUE;
return_false:
LeaveCriticalSection(&pComm->WriteLock);
return FALSE;

View File

@ -316,7 +316,7 @@ static BOOL _set_serial_chars(WINPR_COMM *pComm, const SERIAL_CHARS *pSerialChar
if (pSerialChars->XonChar == pSerialChars->XoffChar)
{
/* http://msdn.microsoft.com/en-us/library/windows/hardware/ff546688%28v=vs.85%29.aspx */
/* https://msdn.microsoft.com/en-us/library/windows/hardware/ff546688?v=vs.85.aspx */
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
@ -360,12 +360,9 @@ static BOOL _set_serial_chars(WINPR_COMM *pComm, const SERIAL_CHARS *pSerialChar
result = FALSE; /* but keep on */
}
/* FIXME: could be implemented during read/write I/O. What about ISIG? */
if (pSerialChars->EventChar != '\0')
{
CommLog_Print(WLOG_WARN, "EventChar 0x%02"PRIX8" ('%c') cannot be set\n", pSerialChars->EventChar, (char) pSerialChars->EventChar);
SetLastError(ERROR_NOT_SUPPORTED);
result = FALSE; /* but keep on */
pComm->eventChar = pSerialChars->EventChar;
}
upcomingTermios.c_cc[VSTART] = pSerialChars->XonChar;
@ -1076,7 +1073,8 @@ static BOOL _set_wait_mask(WINPR_COMM *pComm, const ULONG *pWaitMask)
if (possibleMask != *pWaitMask)
{
CommLog_Print(WLOG_WARN, "Not all wait events supported (Serial.sys), requested events= 0x%08"PRIX32", possible events= 0x%08"PRIX32"", *pWaitMask, possibleMask);
CommLog_Print(WLOG_WARN, "Not all wait events supported (Serial.sys), requested events= 0x%08"PRIX32", possible events= 0x%08"PRIX32"",
*pWaitMask, possibleMask);
/* FIXME: shall we really set the possibleMask and return FALSE? */
pComm->WaitEventMask = possibleMask;
@ -1310,7 +1308,7 @@ static BOOL _get_commstatus(WINPR_COMM *pComm, SERIAL_STATUS *pCommstatus)
if (currentCounters.rx != pComm->counters.rx)
{
pComm->PendingEvents |= SERIAL_EV_RXCHAR;
pComm->PendingEvents |= SERIAL_EV_RXFLAG;
}
if ((currentCounters.tx != pComm->counters.tx) && /* at least a transmission occurred AND ...*/
@ -1458,7 +1456,7 @@ static BOOL _wait_on_mask(WINPR_COMM *pComm, ULONG *pOutputMask)
*
* NOTE: previously used a semaphore but used
* sem_timedwait() anyway. Finally preferred a simpler
* solution with Sleep() whithout the burden of the
* solution with Sleep() without the burden of the
* semaphore initialization and destroying.
*/