From 916e606784e295b681a6a1a27e1a4e4cc213efef Mon Sep 17 00:00:00 2001 From: Ondrej Holy Date: Thu, 8 Dec 2022 14:39:41 +0100 Subject: [PATCH] Fix multiple CVE issues CVE-2022-39316, CVE-2022-39317: Add missing length checks in zgfx CVE-2022-39318: Fix division by zero in urbdrc channel CVE-2022-39319: Add missing length checks in urbdrc channel CVE-2022-39320: Ensure urb_create_iocompletion uses size_t CVE-2022-39347: Fix path validation in drive channel CVE-2022-41877: Add missing length check in drive channel Resolves: #2145140 --- Added-function-_wcsncmp.patch | 62 ++++ ...length-check-in-urb_control_transfer.patch | 29 ++ ...ngth-checks-in-zgfx_decompress_segme.patch | 51 ++++ ...e_iocompletion-uses-size_t-for-calcu.patch | 32 ++ Fixed-division-by-zero-in-urbdrc.patch | 39 +++ ...-input-buffer-length-check-in-urbdrc.patch | 58 ++++ ...ream-length-check-in-drive_file_quer.patch | 28 ++ Fixed-path-validation-in-drive-channel.patch | 288 ++++++++++++++++++ freerdp.spec | 18 ++ winpr-crt-Added-wcsstr-implementation.patch | 66 ++++ ...r-crt-Fix-wcs-cmp-and-wcs-len-checks.patch | 90 ++++++ 11 files changed, 761 insertions(+) create mode 100644 Added-function-_wcsncmp.patch create mode 100644 Added-missing-length-check-in-urb_control_transfer.patch create mode 100644 Added-missing-length-checks-in-zgfx_decompress_segme.patch create mode 100644 Ensure-urb_create_iocompletion-uses-size_t-for-calcu.patch create mode 100644 Fixed-division-by-zero-in-urbdrc.patch create mode 100644 Fixed-missing-input-buffer-length-check-in-urbdrc.patch create mode 100644 Fixed-missing-stream-length-check-in-drive_file_quer.patch create mode 100644 Fixed-path-validation-in-drive-channel.patch create mode 100644 winpr-crt-Added-wcsstr-implementation.patch create mode 100644 winpr-crt-Fix-wcs-cmp-and-wcs-len-checks.patch diff --git a/Added-function-_wcsncmp.patch b/Added-function-_wcsncmp.patch new file mode 100644 index 0000000..cef8a66 --- /dev/null +++ b/Added-function-_wcsncmp.patch @@ -0,0 +1,62 @@ +From e482b394efc371412ce659b731a9b1e1d73bdf0e Mon Sep 17 00:00:00 2001 +From: akallabeth +Date: Mon, 24 Oct 2022 10:42:56 +0200 +Subject: [PATCH] Added function _wcsncmp + +* Compare WCHAR strings up to n characters + +(cherry picked from commit 8178ed26a459356ece17414c6e871a7e0735a4ec) +--- + winpr/include/winpr/string.h | 2 ++ + winpr/libwinpr/crt/string.c | 15 ++++++++++++++- + 2 files changed, 16 insertions(+), 1 deletion(-) + +diff --git a/winpr/include/winpr/string.h b/winpr/include/winpr/string.h +index 8ce83bc1d..3b907c444 100644 +--- a/winpr/include/winpr/string.h ++++ b/winpr/include/winpr/string.h +@@ -57,6 +57,7 @@ extern "C" + WINPR_API int _strnicmp(const char* string1, const char* string2, size_t count); + + WINPR_API int _wcscmp(const WCHAR* string1, const WCHAR* string2); ++ WINPR_API int _wcsncmp(const WCHAR* string1, const WCHAR* string2, size_t count); + + WINPR_API size_t _wcslen(const WCHAR* str); + WINPR_API size_t _wcsnlen(const WCHAR* str, size_t maxNumberOfElements); +@@ -70,6 +71,7 @@ extern "C" + #else + + #define _wcscmp wcscmp ++#define _wcsncmp wcsncmp + #define _wcslen wcslen + #define _wcsnlen wcsnlen + #define _wcschr wcschr +diff --git a/winpr/libwinpr/crt/string.c b/winpr/libwinpr/crt/string.c +index 37fcb4b25..c25ffa279 100644 +--- a/winpr/libwinpr/crt/string.c ++++ b/winpr/libwinpr/crt/string.c +@@ -90,7 +90,20 @@ int _wcscmp(const WCHAR* string1, const WCHAR* string2) + + Data_Read_UINT16(string1, value1); + Data_Read_UINT16(string2, value2); +- return value1 - value2; ++ return (int)value1 - value2; ++} ++ ++int _wcsncmp(const WCHAR* string1, const WCHAR* string2, size_t count) ++{ ++ for (size_t x = 0; x < count; x++) ++ { ++ const WCHAR a = string1[x]; ++ const WCHAR b = string2[x]; ++ ++ if (a != b) ++ return (int)a - b; ++ } ++ return 0; + } + + /* _wcslen -> wcslen */ +-- +2.37.1 + diff --git a/Added-missing-length-check-in-urb_control_transfer.patch b/Added-missing-length-check-in-urb_control_transfer.patch new file mode 100644 index 0000000..406161b --- /dev/null +++ b/Added-missing-length-check-in-urb_control_transfer.patch @@ -0,0 +1,29 @@ +From 8c513f127549433c830575202d1551b0e9dd182d Mon Sep 17 00:00:00 2001 +From: akallabeth +Date: Thu, 13 Oct 2022 09:00:48 +0200 +Subject: [PATCH] Added missing length check in urb_control_transfer + +(cherry picked from commit ce838e2477cb8173ea5e98f35ad55ff41ea5117d) +--- + channels/urbdrc/client/data_transfer.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/channels/urbdrc/client/data_transfer.c b/channels/urbdrc/client/data_transfer.c +index 9a44e6e09..bb2784055 100644 +--- a/channels/urbdrc/client/data_transfer.c ++++ b/channels/urbdrc/client/data_transfer.c +@@ -673,7 +673,11 @@ static UINT urb_control_transfer(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* callba + buffer = Stream_Pointer(out); + + if (transferDir == USBD_TRANSFER_DIRECTION_OUT) ++ { ++ if (!Stream_CheckAndLogRequiredLength(TAG, s, OutputBufferSize)) ++ return ERROR_INVALID_DATA; + Stream_Copy(s, out, OutputBufferSize); ++ } + + /** process TS_URB_CONTROL_TRANSFER */ + if (!pdev->control_transfer(pdev, RequestId, EndpointAddress, TransferFlags, bmRequestType, +-- +2.37.1 + diff --git a/Added-missing-length-checks-in-zgfx_decompress_segme.patch b/Added-missing-length-checks-in-zgfx_decompress_segme.patch new file mode 100644 index 0000000..a478489 --- /dev/null +++ b/Added-missing-length-checks-in-zgfx_decompress_segme.patch @@ -0,0 +1,51 @@ +From babbd1e433d273634637f5199429986714864033 Mon Sep 17 00:00:00 2001 +From: akallabeth +Date: Thu, 13 Oct 2022 09:09:28 +0200 +Subject: [PATCH] Added missing length checks in zgfx_decompress_segment + +(cherry picked from commit 64716b335858109d14f27b51acc4c4d71a92a816) +--- + libfreerdp/codec/zgfx.c | 11 +++++++---- + 1 file changed, 7 insertions(+), 4 deletions(-) + +diff --git a/libfreerdp/codec/zgfx.c b/libfreerdp/codec/zgfx.c +index 1a2878bd9..04ddeadb2 100644 +--- a/libfreerdp/codec/zgfx.c ++++ b/libfreerdp/codec/zgfx.c +@@ -230,19 +230,19 @@ static BOOL zgfx_decompress_segment(ZGFX_CONTEXT* zgfx, wStream* stream, size_t + BYTE* pbSegment; + size_t cbSegment; + +- if (!zgfx || !stream) ++ if (!zgfx || !stream || (segmentSize < 2)) + return FALSE; + + cbSegment = segmentSize - 1; + +- if ((Stream_GetRemainingLength(stream) < segmentSize) || (segmentSize < 1) || +- (segmentSize > UINT32_MAX)) ++ if ((Stream_GetRemainingLength(stream) < segmentSize) || (segmentSize > UINT32_MAX)) + return FALSE; + + Stream_Read_UINT8(stream, flags); /* header (1 byte) */ + zgfx->OutputCount = 0; + pbSegment = Stream_Pointer(stream); +- Stream_Seek(stream, cbSegment); ++ if (!Stream_SafeSeek(stream, cbSegment)) ++ return FALSE; + + if (!(flags & PACKET_COMPRESSED)) + { +@@ -346,6 +346,9 @@ static BOOL zgfx_decompress_segment(ZGFX_CONTEXT* zgfx, wStream* stream, size_t + if (count > sizeof(zgfx->OutputBuffer) - zgfx->OutputCount) + return FALSE; + ++ if (count > zgfx->cBitsRemaining / 8) ++ return FALSE; ++ + CopyMemory(&(zgfx->OutputBuffer[zgfx->OutputCount]), zgfx->pbInputCurrent, + count); + zgfx_history_buffer_ring_write(zgfx, zgfx->pbInputCurrent, count); +-- +2.37.1 + diff --git a/Ensure-urb_create_iocompletion-uses-size_t-for-calcu.patch b/Ensure-urb_create_iocompletion-uses-size_t-for-calcu.patch new file mode 100644 index 0000000..7f0efa4 --- /dev/null +++ b/Ensure-urb_create_iocompletion-uses-size_t-for-calcu.patch @@ -0,0 +1,32 @@ +From b3a695e9f38a42f1ef0cade0d5e1fe60cf68864e Mon Sep 17 00:00:00 2001 +From: akallabeth +Date: Thu, 13 Oct 2022 08:36:26 +0200 +Subject: [PATCH] Ensure urb_create_iocompletion uses size_t for calculation + +(cherry picked from commit de7e0f062ee53d00b4a966a43855a716e3478150) +--- + channels/urbdrc/client/data_transfer.c | 8 +++++++- + 1 file changed, 7 insertions(+), 1 deletion(-) + +diff --git a/channels/urbdrc/client/data_transfer.c b/channels/urbdrc/client/data_transfer.c +index 80e84af48..8642c8506 100644 +--- a/channels/urbdrc/client/data_transfer.c ++++ b/channels/urbdrc/client/data_transfer.c +@@ -97,7 +97,13 @@ static wStream* urb_create_iocompletion(UINT32 InterfaceField, UINT32 MessageId, + UINT32 OutputBufferSize) + { + const UINT32 InterfaceId = (STREAM_ID_PROXY << 30) | (InterfaceField & 0x3FFFFFFF); +- wStream* out = Stream_New(NULL, OutputBufferSize + 28); ++ ++#if UINT32_MAX >= SIZE_MAX ++ if (OutputBufferSize > UINT32_MAX - 28ull) ++ return NULL; ++#endif ++ ++ wStream* out = Stream_New(NULL, OutputBufferSize + 28ull); + + if (!out) + return NULL; +-- +2.37.1 + diff --git a/Fixed-division-by-zero-in-urbdrc.patch b/Fixed-division-by-zero-in-urbdrc.patch new file mode 100644 index 0000000..bc87552 --- /dev/null +++ b/Fixed-division-by-zero-in-urbdrc.patch @@ -0,0 +1,39 @@ +From b9c5e3668c4022b34734ac8ccb07dd044d4ff38c Mon Sep 17 00:00:00 2001 +From: akallabeth +Date: Thu, 13 Oct 2022 08:27:41 +0200 +Subject: [PATCH] Fixed division by zero in urbdrc + +(cherry picked from commit 731f8419d04b481d7160de1f34062d630ed48765) +--- + channels/urbdrc/client/libusb/libusb_udevice.c | 12 +++++++++--- + 1 file changed, 9 insertions(+), 3 deletions(-) + +diff --git a/channels/urbdrc/client/libusb/libusb_udevice.c b/channels/urbdrc/client/libusb/libusb_udevice.c +index aa69890ae..5784d9fe2 100644 +--- a/channels/urbdrc/client/libusb/libusb_udevice.c ++++ b/channels/urbdrc/client/libusb/libusb_udevice.c +@@ -1214,12 +1214,18 @@ static int libusb_udev_isoch_transfer(IUDEVICE* idev, URBDRC_CHANNEL_CALLBACK* c + if (!Buffer) + Stream_Seek(user_data->data, (NumberOfPackets * 12)); + +- iso_packet_size = BufferSize / NumberOfPackets; +- iso_transfer = libusb_alloc_transfer(NumberOfPackets); ++ if (NumberOfPackets > 0) ++ { ++ iso_packet_size = BufferSize / NumberOfPackets; ++ iso_transfer = libusb_alloc_transfer((int)NumberOfPackets); ++ } + + if (iso_transfer == NULL) + { +- WLog_Print(urbdrc->log, WLOG_ERROR, "Error: libusb_alloc_transfer."); ++ WLog_Print(urbdrc->log, WLOG_ERROR, ++ "Error: libusb_alloc_transfer [NumberOfPackets=%" PRIu32 ", BufferSize=%" PRIu32 ++ " ]", ++ NumberOfPackets, BufferSize); + async_transfer_user_data_free(user_data); + return -1; + } +-- +2.37.1 + diff --git a/Fixed-missing-input-buffer-length-check-in-urbdrc.patch b/Fixed-missing-input-buffer-length-check-in-urbdrc.patch new file mode 100644 index 0000000..ea85996 --- /dev/null +++ b/Fixed-missing-input-buffer-length-check-in-urbdrc.patch @@ -0,0 +1,58 @@ +From ddf9b3f852c31311f8d726012131f657c9857276 Mon Sep 17 00:00:00 2001 +From: akallabeth +Date: Thu, 13 Oct 2022 08:47:51 +0200 +Subject: [PATCH] Fixed missing input buffer length check in urbdrc + +(cherry picked from commit 497df00f741dd4fc89292aaef2db7368aee45d0d) +--- + channels/urbdrc/client/data_transfer.c | 20 ++++++++++++++++++++ + 1 file changed, 20 insertions(+) + +diff --git a/channels/urbdrc/client/data_transfer.c b/channels/urbdrc/client/data_transfer.c +index bb2784055..80e84af48 100644 +--- a/channels/urbdrc/client/data_transfer.c ++++ b/channels/urbdrc/client/data_transfer.c +@@ -241,6 +241,10 @@ static UINT urbdrc_process_io_control(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* c + + Stream_Read_UINT32(s, OutputBufferSize); + Stream_Read_UINT32(s, RequestId); ++ ++ if (OutputBufferSize > UINT32_MAX - 4) ++ return ERROR_INVALID_DATA; ++ + InterfaceId = ((STREAM_ID_PROXY << 30) | pdev->get_ReqCompletion(pdev)); + out = urb_create_iocompletion(InterfaceId, MessageId, RequestId, OutputBufferSize + 4); + +@@ -724,6 +728,15 @@ static UINT urb_bulk_or_interrupt_transfer(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBA + Stream_Read_UINT32(s, TransferFlags); /** TransferFlags */ + Stream_Read_UINT32(s, OutputBufferSize); + EndpointAddress = (PipeHandle & 0x000000ff); ++ ++ if (transferDir == USBD_TRANSFER_DIRECTION_OUT) ++ { ++ if (!Stream_CheckAndLogRequiredLength(TAG, s, OutputBufferSize)) ++ { ++ return ERROR_INVALID_DATA; ++ } ++ } ++ + /** process TS_URB_BULK_OR_INTERRUPT_TRANSFER */ + return pdev->bulk_or_interrupt_transfer( + pdev, callback, MessageId, RequestId, EndpointAddress, TransferFlags, noAck, +@@ -808,6 +821,13 @@ static UINT urb_isoch_transfer(IUDEVICE* pdev, URBDRC_CHANNEL_CALLBACK* callback + packetDescriptorData = Stream_Pointer(s); + Stream_Seek(s, NumberOfPackets * 12); + Stream_Read_UINT32(s, OutputBufferSize); ++ ++ if (transferDir == USBD_TRANSFER_DIRECTION_OUT) ++ { ++ if (!Stream_CheckAndLogRequiredLength(TAG, s, OutputBufferSize)) ++ return ERROR_INVALID_DATA; ++ } ++ + return pdev->isoch_transfer( + pdev, callback, MessageId, RequestId, EndpointAddress, TransferFlags, StartFrame, + ErrorCount, noAck, packetDescriptorData, NumberOfPackets, OutputBufferSize, +-- +2.37.1 + diff --git a/Fixed-missing-stream-length-check-in-drive_file_quer.patch b/Fixed-missing-stream-length-check-in-drive_file_quer.patch new file mode 100644 index 0000000..0c31cf5 --- /dev/null +++ b/Fixed-missing-stream-length-check-in-drive_file_quer.patch @@ -0,0 +1,28 @@ +From 80b2483373c00baec3a26b1d82027f16dfdd8859 Mon Sep 17 00:00:00 2001 +From: akallabeth +Date: Mon, 24 Oct 2022 08:45:05 +0200 +Subject: [PATCH] Fixed missing stream length check in + drive_file_query_directory + +(cherry picked from commit 4e4bb79795d6ac85473fb7a83e53ccf63d204b93) +--- + channels/drive/client/drive_main.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/channels/drive/client/drive_main.c b/channels/drive/client/drive_main.c +index d3776381c..b6cf2ad32 100644 +--- a/channels/drive/client/drive_main.c ++++ b/channels/drive/client/drive_main.c +@@ -629,6 +629,9 @@ static UINT drive_process_irp_query_directory(DRIVE_DEVICE* drive, IRP* irp) + Stream_Read_UINT32(irp->input, PathLength); + Stream_Seek(irp->input, 23); /* Padding */ + path = (WCHAR*)Stream_Pointer(irp->input); ++ if (!Stream_CheckAndLogRequiredLength(TAG, irp->input, PathLength)) ++ return ERROR_INVALID_DATA; ++ + file = drive_get_file_by_id(drive, irp->FileId); + + if (file == NULL) +-- +2.37.1 + diff --git a/Fixed-path-validation-in-drive-channel.patch b/Fixed-path-validation-in-drive-channel.patch new file mode 100644 index 0000000..935a047 --- /dev/null +++ b/Fixed-path-validation-in-drive-channel.patch @@ -0,0 +1,288 @@ +From 865ba07a0fd4fbc7a8203482411aacca3bbfbb9f Mon Sep 17 00:00:00 2001 +From: akallabeth +Date: Mon, 24 Oct 2022 10:41:55 +0200 +Subject: [PATCH] Fixed path validation in drive channel + +Check that canonical path is a subpath of the shared directory + +(cherry picked from commit 844c94e6d0438fa7bd8ff8d5513c3f69c3018b85) +--- + channels/drive/client/drive_file.c | 106 ++++++++++++++++++----------- + channels/drive/client/drive_file.h | 8 +-- + channels/drive/client/drive_main.c | 8 +-- + 3 files changed, 73 insertions(+), 49 deletions(-) + +diff --git a/channels/drive/client/drive_file.c b/channels/drive/client/drive_file.c +index 305438593..1ea4ab9da 100644 +--- a/channels/drive/client/drive_file.c ++++ b/channels/drive/client/drive_file.c +@@ -61,10 +61,14 @@ + } while (0) + #endif + +-static void drive_file_fix_path(WCHAR* path) ++static BOOL drive_file_fix_path(WCHAR* path, size_t length) + { + size_t i; +- size_t length = _wcslen(path); ++ ++ if ((length == 0) || (length > UINT32_MAX)) ++ return FALSE; ++ ++ assert(path); + + for (i = 0; i < length; i++) + { +@@ -75,58 +79,82 @@ static void drive_file_fix_path(WCHAR* path) + #ifdef WIN32 + + if ((length == 3) && (path[1] == L':') && (path[2] == L'/')) +- return; ++ return FALSE; + + #else + + if ((length == 1) && (path[0] == L'/')) +- return; ++ return FALSE; + + #endif + + if ((length > 0) && (path[length - 1] == L'/')) + path[length - 1] = L'\0'; ++ ++ return TRUE; + } + + static WCHAR* drive_file_combine_fullpath(const WCHAR* base_path, const WCHAR* path, +- size_t PathLength) ++ size_t PathWCharLength) + { +- WCHAR* fullpath; +- size_t base_path_length; ++ BOOL ok = FALSE; ++ WCHAR* fullpath = NULL; ++ size_t length; + +- if (!base_path || (!path && (PathLength > 0))) +- return NULL; ++ if (!base_path || (!path && (PathWCharLength > 0))) ++ goto fail; + +- base_path_length = _wcslen(base_path) * 2; +- fullpath = (WCHAR*)calloc(1, base_path_length + PathLength + sizeof(WCHAR)); ++ const size_t base_path_length = _wcsnlen(base_path, MAX_PATH); ++ length = base_path_length + PathWCharLength + 1; ++ fullpath = (WCHAR*)calloc(length, sizeof(WCHAR)); + + if (!fullpath) ++ goto fail; ++ ++ CopyMemory(fullpath, base_path, base_path_length * sizeof(WCHAR)); ++ if (path) ++ CopyMemory(&fullpath[base_path_length], path, PathWCharLength * sizeof(WCHAR)); ++ ++ if (!drive_file_fix_path(fullpath, length)) ++ goto fail; ++ ++ /* Ensure the path does not contain sequences like '..' */ ++ const WCHAR dotdot[] = { '.', '.', '\0' }; ++ if (_wcsstr(&fullpath[base_path_length], dotdot)) + { +- WLog_ERR(TAG, "malloc failed!"); +- return NULL; ++ char abuffer[MAX_PATH] = { 0 }; ++ ConvertFromUnicode(CP_UTF8, 0, &fullpath[base_path_length], -1, (char**)&abuffer, ++ ARRAYSIZE(abuffer) - 1, NULL, NULL); ++ ++ WLog_WARN(TAG, "[rdpdr] received invalid file path '%s' from server, aborting!", ++ &abuffer[base_path_length]); ++ goto fail; + } + +- CopyMemory(fullpath, base_path, base_path_length); +- if (path) +- CopyMemory((char*)fullpath + base_path_length, path, PathLength); +- drive_file_fix_path(fullpath); ++ ok = TRUE; ++fail: ++ if (!ok) ++ { ++ free(fullpath); ++ fullpath = NULL; ++ } + return fullpath; + } + + static BOOL drive_file_remove_dir(const WCHAR* path) + { +- WIN32_FIND_DATAW findFileData; ++ WIN32_FIND_DATAW findFileData = { 0 }; + BOOL ret = TRUE; +- HANDLE dir; +- WCHAR* fullpath; +- WCHAR* path_slash; +- size_t base_path_length; ++ HANDLE dir = INVALID_HANDLE_VALUE; ++ WCHAR* fullpath = NULL; ++ WCHAR* path_slash = NULL; ++ size_t base_path_length = 0; + + if (!path) + return FALSE; + +- base_path_length = _wcslen(path) * 2; +- path_slash = (WCHAR*)calloc(1, base_path_length + sizeof(WCHAR) * 3); ++ base_path_length = _wcslen(path); ++ path_slash = (WCHAR*)calloc(base_path_length + 3, sizeof(WCHAR)); + + if (!path_slash) + { +@@ -134,12 +162,11 @@ static BOOL drive_file_remove_dir(const WCHAR* path) + return FALSE; + } + +- CopyMemory(path_slash, path, base_path_length); +- path_slash[base_path_length / 2] = L'/'; +- path_slash[base_path_length / 2 + 1] = L'*'; ++ CopyMemory(path_slash, path, base_path_length * sizeof(WCHAR)); ++ path_slash[base_path_length] = L'/'; ++ path_slash[base_path_length + 1] = L'*'; + DEBUG_WSTR("Search in %s", path_slash); + dir = FindFirstFileW(path_slash, &findFileData); +- path_slash[base_path_length / 2 + 1] = 0; + + if (dir == INVALID_HANDLE_VALUE) + { +@@ -149,7 +176,7 @@ static BOOL drive_file_remove_dir(const WCHAR* path) + + do + { +- size_t len = _wcslen(findFileData.cFileName); ++ const size_t len = _wcsnlen(findFileData.cFileName, ARRAYSIZE(findFileData.cFileName)); + + if ((len == 1 && findFileData.cFileName[0] == L'.') || + (len == 2 && findFileData.cFileName[0] == L'.' && findFileData.cFileName[1] == L'.')) +@@ -157,7 +184,7 @@ static BOOL drive_file_remove_dir(const WCHAR* path) + continue; + } + +- fullpath = drive_file_combine_fullpath(path_slash, findFileData.cFileName, len * 2); ++ fullpath = drive_file_combine_fullpath(path_slash, findFileData.cFileName, len); + DEBUG_WSTR("Delete %s", fullpath); + + if (findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) +@@ -333,13 +360,13 @@ static BOOL drive_file_init(DRIVE_FILE* file) + return file->file_handle != INVALID_HANDLE_VALUE; + } + +-DRIVE_FILE* drive_file_new(const WCHAR* base_path, const WCHAR* path, UINT32 PathLength, UINT32 id, +- UINT32 DesiredAccess, UINT32 CreateDisposition, UINT32 CreateOptions, +- UINT32 FileAttributes, UINT32 SharedAccess) ++DRIVE_FILE* drive_file_new(const WCHAR* base_path, const WCHAR* path, UINT32 PathWCharLength, ++ UINT32 id, UINT32 DesiredAccess, UINT32 CreateDisposition, ++ UINT32 CreateOptions, UINT32 FileAttributes, UINT32 SharedAccess) + { + DRIVE_FILE* file; + +- if (!base_path || (!path && (PathLength > 0))) ++ if (!base_path || (!path && (PathWCharLength > 0))) + return NULL; + + file = (DRIVE_FILE*)calloc(1, sizeof(DRIVE_FILE)); +@@ -359,7 +386,7 @@ DRIVE_FILE* drive_file_new(const WCHAR* base_path, const WCHAR* path, UINT32 Pat + file->CreateDisposition = CreateDisposition; + file->CreateOptions = CreateOptions; + file->SharedAccess = SharedAccess; +- drive_file_set_fullpath(file, drive_file_combine_fullpath(base_path, path, PathLength)); ++ drive_file_set_fullpath(file, drive_file_combine_fullpath(base_path, path, PathWCharLength)); + + if (!drive_file_init(file)) + { +@@ -714,13 +741,10 @@ BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UIN + return FALSE; + + fullpath = drive_file_combine_fullpath(file->basepath, (WCHAR*)Stream_Pointer(input), +- FileNameLength); ++ FileNameLength / sizeof(WCHAR)); + + if (!fullpath) +- { +- WLog_ERR(TAG, "drive_file_combine_fullpath failed!"); + return FALSE; +- } + + #ifdef _WIN32 + +@@ -759,7 +783,7 @@ BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UIN + } + + BOOL drive_file_query_directory(DRIVE_FILE* file, UINT32 FsInformationClass, BYTE InitialQuery, +- const WCHAR* path, UINT32 PathLength, wStream* output) ++ const WCHAR* path, UINT32 PathWCharLength, wStream* output) + { + size_t length; + WCHAR* ent_path; +@@ -773,7 +797,7 @@ BOOL drive_file_query_directory(DRIVE_FILE* file, UINT32 FsInformationClass, BYT + if (file->find_handle != INVALID_HANDLE_VALUE) + FindClose(file->find_handle); + +- ent_path = drive_file_combine_fullpath(file->basepath, path, PathLength); ++ ent_path = drive_file_combine_fullpath(file->basepath, path, PathWCharLength); + /* open new search handle and retrieve the first entry */ + file->find_handle = FindFirstFileW(ent_path, &file->find_data); + free(ent_path); +diff --git a/channels/drive/client/drive_file.h b/channels/drive/client/drive_file.h +index ed789d6f0..6d3bd7045 100644 +--- a/channels/drive/client/drive_file.h ++++ b/channels/drive/client/drive_file.h +@@ -51,9 +51,9 @@ struct _DRIVE_FILE + UINT32 CreateOptions; + }; + +-DRIVE_FILE* drive_file_new(const WCHAR* base_path, const WCHAR* path, UINT32 PathLength, UINT32 id, +- UINT32 DesiredAccess, UINT32 CreateDisposition, UINT32 CreateOptions, +- UINT32 FileAttributes, UINT32 SharedAccess); ++DRIVE_FILE* drive_file_new(const WCHAR* base_path, const WCHAR* path, UINT32 PathWCharLength, ++ UINT32 id, UINT32 DesiredAccess, UINT32 CreateDisposition, ++ UINT32 CreateOptions, UINT32 FileAttributes, UINT32 SharedAccess); + BOOL drive_file_free(DRIVE_FILE* file); + + BOOL drive_file_open(DRIVE_FILE* file); +@@ -64,6 +64,6 @@ BOOL drive_file_query_information(DRIVE_FILE* file, UINT32 FsInformationClass, w + BOOL drive_file_set_information(DRIVE_FILE* file, UINT32 FsInformationClass, UINT32 Length, + wStream* input); + BOOL drive_file_query_directory(DRIVE_FILE* file, UINT32 FsInformationClass, BYTE InitialQuery, +- const WCHAR* path, UINT32 PathLength, wStream* output); ++ const WCHAR* path, UINT32 PathWCharLength, wStream* output); + + #endif /* FREERDP_CHANNEL_DRIVE_FILE_H */ +diff --git a/channels/drive/client/drive_main.c b/channels/drive/client/drive_main.c +index 1b5422522..d3776381c 100644 +--- a/channels/drive/client/drive_main.c ++++ b/channels/drive/client/drive_main.c +@@ -184,8 +184,8 @@ static UINT drive_process_irp_create(DRIVE_DEVICE* drive, IRP* irp) + + path = (const WCHAR*)Stream_Pointer(irp->input); + FileId = irp->devman->id_sequence++; +- file = drive_file_new(drive->path, path, PathLength, FileId, DesiredAccess, CreateDisposition, +- CreateOptions, FileAttributes, SharedAccess); ++ file = drive_file_new(drive->path, path, PathLength / sizeof(WCHAR), FileId, DesiredAccess, ++ CreateDisposition, CreateOptions, FileAttributes, SharedAccess); + + if (!file) + { +@@ -636,8 +636,8 @@ static UINT drive_process_irp_query_directory(DRIVE_DEVICE* drive, IRP* irp) + irp->IoStatus = STATUS_UNSUCCESSFUL; + Stream_Write_UINT32(irp->output, 0); /* Length */ + } +- else if (!drive_file_query_directory(file, FsInformationClass, InitialQuery, path, PathLength, +- irp->output)) ++ else if (!drive_file_query_directory(file, FsInformationClass, InitialQuery, path, ++ PathLength / sizeof(WCHAR), irp->output)) + { + irp->IoStatus = drive_map_windows_err(GetLastError()); + } +-- +2.37.1 + diff --git a/freerdp.spec b/freerdp.spec index f42632f..befa695 100644 --- a/freerdp.spec +++ b/freerdp.spec @@ -46,6 +46,18 @@ Patch4: Fix-length-checks-in-parallel-driver.patch # https://bugzilla.redhat.com/show_bug.cgi?id=2136154 Patch5: Fixed-missing-length-check-in-video-channel.patch +# https://bugzilla.redhat.com/show_bug.cgi?id=2145140 +Patch6: Added-missing-length-checks-in-zgfx_decompress_segme.patch +Patch7: Fixed-division-by-zero-in-urbdrc.patch +Patch8: Added-missing-length-check-in-urb_control_transfer.patch +Patch9: Fixed-missing-input-buffer-length-check-in-urbdrc.patch +Patch10: Ensure-urb_create_iocompletion-uses-size_t-for-calcu.patch +Patch11: Added-function-_wcsncmp.patch +Patch12: winpr-crt-Fix-wcs-cmp-and-wcs-len-checks.patch +Patch13: winpr-crt-Added-wcsstr-implementation.patch +Patch14: Fixed-path-validation-in-drive-channel.patch +Patch15: Fixed-missing-stream-length-check-in-drive_file_quer.patch + BuildRequires: gcc BuildRequires: gcc-c++ BuildRequires: alsa-lib-devel @@ -314,6 +326,12 @@ find %{buildroot} -name "*.a" -delete * Thu Dec 08 2022 Ondrej Holy - - 2:2.4.1-4 - CVE-2022-39282: Fix length checks in parallel driver (#2136152) - CVE-2022-39283: Add missing length check in video channel (#2136154) +- CVE-2022-39316, CVE-2022-39317: Add missing length checks in zgfx (#2145140) +- CVE-2022-39318: Fix division by zero in urbdrc channel (#2145140) +- CVE-2022-39319: Add missing length checks in urbdrc channel (#2145140) +- CVE-2022-39320: Ensure urb_create_iocompletion uses size_t (#2145140) +- CVE-2022-39347: Fix path validation in drive channel (#2145140) +- CVE-2022-41877: Add missing length check in drive channel (#2145140) * Wed Jun 22 2022 Ondrej Holy - - 2:2.4.1-3 - Fix gateway functionality with OpenSSL 3.0 (#2023262) diff --git a/winpr-crt-Added-wcsstr-implementation.patch b/winpr-crt-Added-wcsstr-implementation.patch new file mode 100644 index 0000000..533ef44 --- /dev/null +++ b/winpr-crt-Added-wcsstr-implementation.patch @@ -0,0 +1,66 @@ +From ddc6dacd06b41ed5001b1c884b5d5c9e0a70e275 Mon Sep 17 00:00:00 2001 +From: akallabeth +Date: Thu, 10 Nov 2022 15:54:28 +0100 +Subject: [PATCH] [winpr, crt] Added wcsstr implementation + +(cherry picked from commit 6c034ba6117a4efc9266e845fe9a9a92ed4ee61d) +--- + winpr/include/winpr/string.h | 3 +++ + winpr/libwinpr/crt/string.c | 20 ++++++++++++++++++++ + 2 files changed, 23 insertions(+) + +diff --git a/winpr/include/winpr/string.h b/winpr/include/winpr/string.h +index 3b907c444..2d7126210 100644 +--- a/winpr/include/winpr/string.h ++++ b/winpr/include/winpr/string.h +@@ -62,6 +62,8 @@ extern "C" + WINPR_API size_t _wcslen(const WCHAR* str); + WINPR_API size_t _wcsnlen(const WCHAR* str, size_t maxNumberOfElements); + ++ WINPR_API WCHAR* _wcsstr(const WCHAR* str, const WCHAR* strSearch); ++ + WINPR_API WCHAR* _wcschr(const WCHAR* str, WCHAR c); + WINPR_API WCHAR* _wcsrchr(const WCHAR* str, WCHAR c); + +@@ -74,6 +76,7 @@ extern "C" + #define _wcsncmp wcsncmp + #define _wcslen wcslen + #define _wcsnlen wcsnlen ++#define _wcsstr wcsstr + #define _wcschr wcschr + #define _wcsrchr wcsrchr + +diff --git a/winpr/libwinpr/crt/string.c b/winpr/libwinpr/crt/string.c +index 5dcf4b3f1..efd7d166c 100644 +--- a/winpr/libwinpr/crt/string.c ++++ b/winpr/libwinpr/crt/string.c +@@ -147,6 +147,26 @@ size_t _wcsnlen(const WCHAR* str, size_t max) + return x; + } + ++/* _wcsstr -> wcsstr */ ++ ++WCHAR* _wcsstr(const WCHAR* str, const WCHAR* strSearch) ++{ ++ assert(str); ++ assert(strSearch); ++ ++ if (strSearch[0] == '\0') ++ return str; ++ ++ const size_t searchLen = _wcslen(strSearch); ++ while (*str) ++ { ++ if (_wcsncmp(str, strSearch, searchLen) == 0) ++ return str; ++ str++; ++ } ++ return NULL; ++} ++ + /* _wcschr -> wcschr */ + + WCHAR* _wcschr(const WCHAR* str, WCHAR c) +-- +2.37.1 + diff --git a/winpr-crt-Fix-wcs-cmp-and-wcs-len-checks.patch b/winpr-crt-Fix-wcs-cmp-and-wcs-len-checks.patch new file mode 100644 index 0000000..1ae664d --- /dev/null +++ b/winpr-crt-Fix-wcs-cmp-and-wcs-len-checks.patch @@ -0,0 +1,90 @@ +From fb9d753af70b449dd7a17898d46fd57822a08dc1 Mon Sep 17 00:00:00 2001 +From: akallabeth +Date: Thu, 10 Nov 2022 14:21:22 +0100 +Subject: [PATCH] [winpr, crt] Fix wcs*cmp and wcs*len checks + +(cherry picked from commit b60fac1a0470fe83e8d0b448f0fd7e9e6d6a0f96) +--- + winpr/libwinpr/crt/string.c | 30 +++++++++++++++++++----------- + 1 file changed, 19 insertions(+), 11 deletions(-) + +diff --git a/winpr/libwinpr/crt/string.c b/winpr/libwinpr/crt/string.c +index c25ffa279..5dcf4b3f1 100644 +--- a/winpr/libwinpr/crt/string.c ++++ b/winpr/libwinpr/crt/string.c +@@ -26,6 +26,7 @@ + #include + + #include ++#include + #include + + /* String Manipulation (CRT): http://msdn.microsoft.com/en-us/library/f0151s4x.aspx */ +@@ -80,21 +81,28 @@ int _strnicmp(const char* string1, const char* string2, size_t count) + + int _wcscmp(const WCHAR* string1, const WCHAR* string2) + { +- WCHAR value1, value2; ++ assert(string1); ++ assert(string2); + +- while (*string1 && (*string1 == *string2)) ++ while (TRUE) + { +- string1++; +- string2++; ++ const WCHAR w1 = *string1++; ++ const WCHAR w2 = *string2++; ++ ++ if (w1 != w2) ++ return (int)w1 - w2; ++ else if ((w1 == '\0') || (w2 == '\0')) ++ return (int)w1 - w2; + } + +- Data_Read_UINT16(string1, value1); +- Data_Read_UINT16(string2, value2); +- return (int)value1 - value2; ++ return 0; + } + + int _wcsncmp(const WCHAR* string1, const WCHAR* string2, size_t count) + { ++ assert(string1); ++ assert(string2); ++ + for (size_t x = 0; x < count; x++) + { + const WCHAR a = string1[x]; +@@ -102,6 +110,8 @@ int _wcsncmp(const WCHAR* string1, const WCHAR* string2, size_t count) + + if (a != b) + return (int)a - b; ++ else if ((a == '\0') || (b == '\0')) ++ return (int)a - b; + } + return 0; + } +@@ -112,8 +122,7 @@ size_t _wcslen(const WCHAR* str) + { + const WCHAR* p = (const WCHAR*)str; + +- if (!p) +- return 0; ++ assert(p); + + while (*p) + p++; +@@ -127,8 +136,7 @@ size_t _wcsnlen(const WCHAR* str, size_t max) + { + size_t x; + +- if (!str) +- return 0; ++ assert(str); + + for (x = 0; x < max; x++) + { +-- +2.37.1 +