import Oracle_OSS freerdp-3.10.3-12.el10_2.8
This commit is contained in:
parent
3392ca130c
commit
67e786c1d0
37
channels-audin-limit-FramesPerPacket.patch
Normal file
37
channels-audin-limit-FramesPerPacket.patch
Normal file
@ -0,0 +1,37 @@
|
||||
From 18deeba63c4091dfa96973a02df5bc214b4844c3 Mon Sep 17 00:00:00 2001
|
||||
From: Armin Novak <armin.novak@thincast.com>
|
||||
Date: Sun, 12 Jul 2026 17:37:48 +0200
|
||||
Subject: [PATCH] [channels,audin] limit FramesPerPacket
|
||||
|
||||
---
|
||||
channels/audin/client/audin_main.c | 10 +++++++++-
|
||||
1 file changed, 9 insertions(+), 1 deletion(-)
|
||||
|
||||
diff --git a/channels/audin/client/audin_main.c b/channels/audin/client/audin_main.c
|
||||
index 23093fb8e..7c403cbbb 100644
|
||||
--- a/channels/audin/client/audin_main.c
|
||||
+++ b/channels/audin/client/audin_main.c
|
||||
@@ -485,7 +485,6 @@ static UINT audin_process_open(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* call
|
||||
Stream_Read_UINT32(s, initialFormat);
|
||||
WLog_Print(audin->log, WLOG_DEBUG, "FramesPerPacket=%" PRIu32 " initialFormat=%" PRIu32 "",
|
||||
FramesPerPacket, initialFormat);
|
||||
- audin->FramesPerPacket = FramesPerPacket;
|
||||
|
||||
if (initialFormat >= callback->formats_count)
|
||||
{
|
||||
@@ -494,6 +493,15 @@ static UINT audin_process_open(AUDIN_PLUGIN* audin, AUDIN_CHANNEL_CALLBACK* call
|
||||
return ERROR_INVALID_DATA;
|
||||
}
|
||||
|
||||
+ /* The RDP protocol field allows UINT32_MAX, but most backend API use INT32 as input parameter
|
||||
+ * or do some math with it, so ensure that the value does not exceed reasonable limits */
|
||||
+ if (FramesPerPacket >= INT32_MAX)
|
||||
+ {
|
||||
+ WLog_Print(audin->log, WLOG_ERROR, "invalid frames per packet %" PRIu32, FramesPerPacket);
|
||||
+ return ERROR_INVALID_DATA;
|
||||
+ }
|
||||
+
|
||||
+ audin->FramesPerPacket = FramesPerPacket;
|
||||
audin->format = &callback->formats[initialFormat];
|
||||
|
||||
if (!audin_open_device(audin, callback))
|
||||
228
channels-audin-tighten-parameter-checks.patch
Normal file
228
channels-audin-tighten-parameter-checks.patch
Normal file
@ -0,0 +1,228 @@
|
||||
From 3b25c78c98d25b23246a5267d45f3654c2a8735d Mon Sep 17 00:00:00 2001
|
||||
From: Armin Novak <armin.novak@thincast.com>
|
||||
Date: Wed, 15 Jul 2026 17:52:28 +0200
|
||||
Subject: [PATCH] [channels,audin] tighten parameter checks
|
||||
|
||||
---
|
||||
channels/audin/client/alsa/audin_alsa.c | 4 +-
|
||||
channels/audin/client/opensles/opensl_io.c | 43 +++++++++++++++-------
|
||||
channels/audin/client/opensles/opensl_io.h | 5 +--
|
||||
channels/audin/client/oss/audin_oss.c | 3 ++
|
||||
channels/audin/client/sndio/audin_sndio.c | 9 +++--
|
||||
channels/audin/client/winmm/audin_winmm.c | 17 +++++----
|
||||
6 files changed, 51 insertions(+), 30 deletions(-)
|
||||
|
||||
diff --git a/channels/audin/client/alsa/audin_alsa.c b/channels/audin/client/alsa/audin_alsa.c
|
||||
index e74097129..5b9f4ea5b 100644
|
||||
--- a/channels/audin/client/alsa/audin_alsa.c
|
||||
+++ b/channels/audin/client/alsa/audin_alsa.c
|
||||
@@ -138,8 +138,8 @@ static DWORD WINAPI audin_alsa_thread_func(LPVOID arg)
|
||||
goto out;
|
||||
}
|
||||
|
||||
- buffer =
|
||||
- (BYTE*)calloc(alsa->frames_per_packet + alsa->aformat.nBlockAlign, alsa->bytes_per_frame);
|
||||
+ buffer = (BYTE*)calloc(1ull * alsa->frames_per_packet + alsa->aformat.nBlockAlign,
|
||||
+ alsa->bytes_per_frame);
|
||||
|
||||
if (!buffer)
|
||||
{
|
||||
diff --git a/channels/audin/client/opensles/opensl_io.c b/channels/audin/client/opensles/opensl_io.c
|
||||
index 39b3dc848..2f27bd60f 100644
|
||||
--- a/channels/audin/client/opensles/opensl_io.c
|
||||
+++ b/channels/audin/client/opensles/opensl_io.c
|
||||
@@ -54,10 +54,10 @@ struct opensl_stream
|
||||
SLRecordItf recorderRecord;
|
||||
SLAndroidSimpleBufferQueueItf recorderBufferQueue;
|
||||
|
||||
- unsigned int inchannels;
|
||||
- unsigned int sr;
|
||||
- unsigned int buffersize;
|
||||
- unsigned int bits_per_sample;
|
||||
+ size_t inchannels;
|
||||
+ size_t sr;
|
||||
+ size_t buffersize;
|
||||
+ size_t bits_per_sample;
|
||||
|
||||
queue_element* prep;
|
||||
queue_element* next;
|
||||
@@ -109,8 +109,8 @@ engine_end:
|
||||
static SLresult openSLRecOpen(OPENSL_STREAM* p)
|
||||
{
|
||||
SLresult result;
|
||||
- SLuint32 sr = p->sr;
|
||||
- SLuint32 channels = p->inchannels;
|
||||
+ SLuint32 sr = WINPR_ASSERTING_INT_CAST(SLuint32, p->sr);
|
||||
+ SLuint32 channels = WINPR_ASSERTING_INT_CAST(SLuint32, p->inchannels);
|
||||
WINPR_ASSERT(!p->recorderObject);
|
||||
|
||||
if (channels)
|
||||
@@ -201,7 +201,10 @@ static SLresult openSLRecOpen(OPENSL_STREAM* p)
|
||||
format_pcm.containerSize = 8;
|
||||
}
|
||||
else
|
||||
- WINPR_ASSERT(0);
|
||||
+ {
|
||||
+ WLog_ERR(TAG, "bits_per_sample=%" PRIuz, p->bits_per_sample);
|
||||
+ return -1;
|
||||
+ }
|
||||
|
||||
SLDataSink audioSnk = { &loc_bq, &format_pcm };
|
||||
// create audio recorder
|
||||
@@ -306,24 +309,31 @@ static void opensles_queue_element_free(void* obj)
|
||||
}
|
||||
|
||||
// open the android audio device for input
|
||||
-OPENSL_STREAM* android_OpenRecDevice(void* context, opensl_receive_t receive, int sr,
|
||||
- int inchannels, int bufferframes, int bits_per_sample)
|
||||
+OPENSL_STREAM* android_OpenRecDevice(void* context, opensl_receive_t receive, size_t sr,
|
||||
+ size_t inchannels, size_t bufferframes, size_t bits_per_sample)
|
||||
{
|
||||
- OPENSL_STREAM* p;
|
||||
-
|
||||
if (!context || !receive)
|
||||
return NULL;
|
||||
|
||||
- p = (OPENSL_STREAM*)calloc(1, sizeof(OPENSL_STREAM));
|
||||
+ OPENSL_STREAM* p = (OPENSL_STREAM*)calloc(1, sizeof(OPENSL_STREAM));
|
||||
|
||||
if (!p)
|
||||
return NULL;
|
||||
|
||||
p->context = context;
|
||||
p->receive = receive;
|
||||
+ if (inchannels > INT32_MAX)
|
||||
+ goto fail;
|
||||
p->inchannels = inchannels;
|
||||
+
|
||||
+ if (sr > INT32_MAX)
|
||||
+ goto fail;
|
||||
p->sr = sr;
|
||||
+
|
||||
+ if (bufferframes > SIZE_MAX / 2)
|
||||
+ goto fail;
|
||||
p->buffersize = bufferframes;
|
||||
+
|
||||
p->bits_per_sample = bits_per_sample;
|
||||
|
||||
if ((p->bits_per_sample != 8) && (p->bits_per_sample != 16))
|
||||
@@ -335,9 +345,14 @@ OPENSL_STREAM* android_OpenRecDevice(void* context, opensl_receive_t receive, in
|
||||
if (openSLRecOpen(p) != SL_RESULT_SUCCESS)
|
||||
goto fail;
|
||||
|
||||
+ const size_t bytesPerSample = p->bits_per_sample / 8ull;
|
||||
+ if (p->buffersize >= SIZE_MAX / bytesPerSample)
|
||||
+ goto fail;
|
||||
+
|
||||
+ const size_t queuesize = p->buffersize * bytesPerSample;
|
||||
/* Create receive buffers, prepare them and start recording */
|
||||
- p->prep = opensles_queue_element_new(p->buffersize * p->bits_per_sample / 8);
|
||||
- p->next = opensles_queue_element_new(p->buffersize * p->bits_per_sample / 8);
|
||||
+ p->prep = opensles_queue_element_new(queuesize);
|
||||
+ p->next = opensles_queue_element_new(queuesize);
|
||||
|
||||
if (!p->prep || !p->next)
|
||||
goto fail;
|
||||
diff --git a/channels/audin/client/opensles/opensl_io.h b/channels/audin/client/opensles/opensl_io.h
|
||||
index e99522cfe..07255de5c 100644
|
||||
--- a/channels/audin/client/opensles/opensl_io.h
|
||||
+++ b/channels/audin/client/opensles/opensl_io.h
|
||||
@@ -51,13 +51,12 @@ extern "C"
|
||||
size in frames. Returns a handle to the OpenSL stream
|
||||
*/
|
||||
FREERDP_LOCAL OPENSL_STREAM* android_OpenRecDevice(void* context, opensl_receive_t receive,
|
||||
- int sr, int inchannels, int bufferframes,
|
||||
- int bits_per_sample);
|
||||
+ size_t sr, size_t inchannels,
|
||||
+ size_t bufferframes, size_t bits_per_sample);
|
||||
/*
|
||||
Close the audio device
|
||||
*/
|
||||
FREERDP_LOCAL void android_CloseRecDevice(OPENSL_STREAM* p);
|
||||
-
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
diff --git a/channels/audin/client/oss/audin_oss.c b/channels/audin/client/oss/audin_oss.c
|
||||
index 8b6ad6cc5..c76326d9c 100644
|
||||
--- a/channels/audin/client/oss/audin_oss.c
|
||||
+++ b/channels/audin/client/oss/audin_oss.c
|
||||
@@ -229,6 +229,9 @@ static DWORD WINAPI audin_oss_thread_func(LPVOID arg)
|
||||
|
||||
buffer_size =
|
||||
(1ull * oss->FramesPerPacket * oss->format.nChannels * (oss->format.wBitsPerSample / 8ull));
|
||||
+ if (buffer_size > INT32_MAX)
|
||||
+ goto err_out;
|
||||
+
|
||||
buffer = (BYTE*)calloc((buffer_size + sizeof(void*)), sizeof(BYTE));
|
||||
|
||||
if (NULL == buffer)
|
||||
diff --git a/channels/audin/client/sndio/audin_sndio.c b/channels/audin/client/sndio/audin_sndio.c
|
||||
index af5426e72..655145db0 100644
|
||||
--- a/channels/audin/client/sndio/audin_sndio.c
|
||||
+++ b/channels/audin/client/sndio/audin_sndio.c
|
||||
@@ -82,7 +82,7 @@ static void* audin_sndio_thread_func(void* arg)
|
||||
struct sio_hdl* hdl;
|
||||
struct sio_par par;
|
||||
BYTE* buffer = NULL;
|
||||
- size_t n, nbytes;
|
||||
+ size_t n;
|
||||
AudinSndioDevice* sndio = (AudinSndioDevice*)arg;
|
||||
UINT error = 0;
|
||||
DWORD status;
|
||||
@@ -125,8 +125,11 @@ static void* audin_sndio_thread_func(void* arg)
|
||||
goto err_out;
|
||||
}
|
||||
|
||||
- nbytes =
|
||||
- (sndio->FramesPerPacket * sndio->format.nChannels * (sndio->format.wBitsPerSample / 8));
|
||||
+ const size_t nbytes = (1ull * sndio->FramesPerPacket * sndio->format.nChannels *
|
||||
+ (sndio->format.wBitsPerSample / 8));
|
||||
+ if (nbytes > INT32_MAX)
|
||||
+ goto err_out;
|
||||
+
|
||||
buffer = (BYTE*)calloc((nbytes + sizeof(void*)), sizeof(BYTE));
|
||||
|
||||
if (buffer == NULL)
|
||||
diff --git a/channels/audin/client/winmm/audin_winmm.c b/channels/audin/client/winmm/audin_winmm.c
|
||||
index daa59254f..d6cceaf18 100644
|
||||
--- a/channels/audin/client/winmm/audin_winmm.c
|
||||
+++ b/channels/audin/client/winmm/audin_winmm.c
|
||||
@@ -169,8 +169,6 @@ static BOOL test_format_supported(const PWAVEFORMATEX pwfx)
|
||||
static DWORD WINAPI audin_winmm_thread_func(LPVOID arg)
|
||||
{
|
||||
AudinWinmmDevice* winmm = (AudinWinmmDevice*)arg;
|
||||
- char* buffer = NULL;
|
||||
- int size = 0;
|
||||
WAVEHDR waveHdr[4] = { 0 };
|
||||
DWORD status = 0;
|
||||
MMRESULT rc = 0;
|
||||
@@ -184,19 +182,22 @@ static DWORD WINAPI audin_winmm_thread_func(LPVOID arg)
|
||||
return ERROR_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
- size =
|
||||
- (winmm->pwfx_cur->wBitsPerSample * winmm->pwfx_cur->nChannels * winmm->frames_per_packet +
|
||||
- 7) /
|
||||
- 8;
|
||||
+ const size_t framesize =
|
||||
+ 1ull * winmm->pwfx_cur->wBitsPerSample / 8ull * winmm->pwfx_cur->nChannels;
|
||||
+ if (framesize > UINT32_MAX)
|
||||
+ return ERROR_INTERNAL_ERROR;
|
||||
|
||||
+ const size_t size = framesize * winmm->frames_per_packet;
|
||||
+ if (size > UINT32_MAX)
|
||||
+ return ERROR_INTERNAL_ERROR;
|
||||
for (int i = 0; i < 4; i++)
|
||||
{
|
||||
- buffer = (char*)malloc(size);
|
||||
+ char* buffer = (char*)calloc(framesize, winmm->frames_per_packet);
|
||||
|
||||
if (!buffer)
|
||||
return CHANNEL_RC_NO_MEMORY;
|
||||
|
||||
- waveHdr[i].dwBufferLength = size;
|
||||
+ waveHdr[i].dwBufferLength = WINPR_ASSERTING_INT_CAST(DWORD, size);
|
||||
waveHdr[i].dwFlags = 0;
|
||||
waveHdr[i].lpData = buffer;
|
||||
rc = waveInPrepareHeader(winmm->hWaveIn, &waveHdr[i], sizeof(waveHdr[i]));
|
||||
51
client-common-deactivate-cli-parsing-in-rdp-files.patch
Normal file
51
client-common-deactivate-cli-parsing-in-rdp-files.patch
Normal file
@ -0,0 +1,51 @@
|
||||
From c4286faee798f10cfa9897f8c482439d1e0a1a83 Mon Sep 17 00:00:00 2001
|
||||
From: Armin Novak <armin.novak@thincast.com>
|
||||
Date: Thu, 2 Jul 2026 10:21:54 +0200
|
||||
Subject: [PATCH] [client,common] deactivate cli parsing in RDP files
|
||||
|
||||
This feature was uncodumented and might have unintended side effects.
|
||||
Deactivate it by default and (for the time being) keep an option to
|
||||
enable it at compile time.
|
||||
---
|
||||
client/common/CMakeLists.txt | 5 +++++
|
||||
client/common/file.c | 4 ++++
|
||||
2 files changed, 9 insertions(+)
|
||||
|
||||
diff --git a/client/common/CMakeLists.txt b/client/common/CMakeLists.txt
|
||||
index fedac6c5e..dc6fde72a 100644
|
||||
--- a/client/common/CMakeLists.txt
|
||||
+++ b/client/common/CMakeLists.txt
|
||||
@@ -47,6 +47,11 @@ else()
|
||||
set(OPT_FUSE_DEFAULT OFF)
|
||||
endif()
|
||||
|
||||
+option(WITH_EMBEDDED_CLI_IN_RDP_FILES "[dangrous] allow embedded cli arguments in rdp files" OFF)
|
||||
+if(WITH_EMBEDDED_CLI_IN_RDP_FILES)
|
||||
+ add_compile_definitions(WITH_EMBEDDED_CLI_IN_RDP_FILES)
|
||||
+endif()
|
||||
+
|
||||
option(WITH_FUSE "Build clipboard with FUSE file copy support" ${OPT_FUSE_DEFAULT})
|
||||
if(WITH_FUSE)
|
||||
find_package(PkgConfig REQUIRED)
|
||||
diff --git a/client/common/file.c b/client/common/file.c
|
||||
index f178cad23..696775361 100644
|
||||
--- a/client/common/file.c
|
||||
+++ b/client/common/file.c
|
||||
@@ -881,13 +881,17 @@ static BOOL parse_line(rdpFile* file, char* line, size_t length, rdp_file_fkt_pa
|
||||
|
||||
const char* beg = line;
|
||||
#if !defined(WITHOUT_FREERDP_3x_DEPRECATED)
|
||||
+#if defined(WITH_EMBEDDED_CLI_IN_RDP_FILES)
|
||||
if (beg[0] == '/')
|
||||
{
|
||||
+ WLog_WARN(TAG, "Parsing CLI options within an RDP file is deprecated and "
|
||||
+ "will be removed in FreeRDP 4.0");
|
||||
if (!freerdp_client_add_option(file, line))
|
||||
return FALSE;
|
||||
|
||||
return TRUE; /* FreeRDP option */
|
||||
}
|
||||
+#endif
|
||||
#endif
|
||||
|
||||
char* d1 = strchr(line, ':');
|
||||
191
client-common-deprecate-cli-options-in-rdp-files.patch
Normal file
191
client-common-deprecate-cli-options-in-rdp-files.patch
Normal file
@ -0,0 +1,191 @@
|
||||
From 802647fa254b761dc01240bcf4e94740aa39e894 Mon Sep 17 00:00:00 2001
|
||||
From: Armin Novak <armin.novak@thincast.com>
|
||||
Date: Thu, 2 Jul 2026 08:34:18 +0200
|
||||
Subject: [PATCH] [client,common] deprecate freerdp command line options in rdp
|
||||
files
|
||||
|
||||
---
|
||||
client/common/file.c | 140 ++++++++++++++++++++-----------------------
|
||||
1 file changed, 64 insertions(+), 76 deletions(-)
|
||||
|
||||
diff --git a/client/common/file.c b/client/common/file.c
|
||||
index 35e8643f2..f178cad23 100644
|
||||
--- a/client/common/file.c
|
||||
+++ b/client/common/file.c
|
||||
@@ -774,16 +774,6 @@ static SSIZE_T freerdp_client_rdp_file_add_line(rdpFile* file)
|
||||
return index;
|
||||
}
|
||||
|
||||
-static BOOL freerdp_client_parse_rdp_file_string(rdpFile* file, char* name, char* value)
|
||||
-{
|
||||
- return freerdp_client_rdp_file_set_string(file, name, value);
|
||||
-}
|
||||
-
|
||||
-static BOOL freerdp_client_parse_rdp_file_option(rdpFile* file, const char* option)
|
||||
-{
|
||||
- return freerdp_client_add_option(file, option);
|
||||
-}
|
||||
-
|
||||
BOOL freerdp_client_parse_rdp_file_buffer(rdpFile* file, const BYTE* buffer, size_t size)
|
||||
{
|
||||
return freerdp_client_parse_rdp_file_buffer_ex(file, buffer, size, NULL);
|
||||
@@ -884,19 +874,67 @@ static BOOL trim_strings(rdpFile* file)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
+static BOOL parse_line(rdpFile* file, char* line, size_t length, rdp_file_fkt_parse parse)
|
||||
+{
|
||||
+ if (length <= 1)
|
||||
+ return TRUE;
|
||||
+
|
||||
+ const char* beg = line;
|
||||
+#if !defined(WITHOUT_FREERDP_3x_DEPRECATED)
|
||||
+ if (beg[0] == '/')
|
||||
+ {
|
||||
+ if (!freerdp_client_add_option(file, line))
|
||||
+ return FALSE;
|
||||
+
|
||||
+ return TRUE; /* FreeRDP option */
|
||||
+ }
|
||||
+#endif
|
||||
+
|
||||
+ char* d1 = strchr(line, ':');
|
||||
+
|
||||
+ if (!d1)
|
||||
+ return TRUE; /* not first delimiter */
|
||||
+
|
||||
+ const char* type = &d1[1];
|
||||
+ char* d2 = strchr(type, ':');
|
||||
+
|
||||
+ if (!d2)
|
||||
+ return TRUE; /* no second delimiter */
|
||||
+
|
||||
+ if ((d2 - d1) != 2)
|
||||
+ return TRUE; /* improper type length */
|
||||
+
|
||||
+ *d1 = 0;
|
||||
+ *d2 = 0;
|
||||
+ const char* name = beg;
|
||||
+ const char* value = &d2[1];
|
||||
+
|
||||
+ if (parse && parse(file->context, name, *type, value))
|
||||
+ return TRUE;
|
||||
+
|
||||
+ if (*type == 'i')
|
||||
+ {
|
||||
+ /* integer type */
|
||||
+ return freerdp_client_parse_rdp_file_integer(file, name, value);
|
||||
+ }
|
||||
+ if (*type == 's')
|
||||
+ {
|
||||
+ /* string type */
|
||||
+ return freerdp_client_rdp_file_set_string(file, name, value);
|
||||
+ }
|
||||
+ if (*type == 'b')
|
||||
+ {
|
||||
+ /* binary type */
|
||||
+ WLog_ERR(TAG, "Unsupported RDP file binary option %s [value=%s]", name, value);
|
||||
+ }
|
||||
+
|
||||
+ return TRUE;
|
||||
+}
|
||||
+
|
||||
BOOL freerdp_client_parse_rdp_file_buffer_ex(rdpFile* file, const BYTE* buffer, size_t size,
|
||||
rdp_file_fkt_parse parse)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
- size_t length = 0;
|
||||
- char* line = NULL;
|
||||
- char* type = NULL;
|
||||
- char* context = NULL;
|
||||
- char* d1 = NULL;
|
||||
- char* d2 = NULL;
|
||||
- char* beg = NULL;
|
||||
- char* name = NULL;
|
||||
- char* value = NULL;
|
||||
char* copy = NULL;
|
||||
|
||||
if (!file)
|
||||
@@ -907,9 +945,8 @@ BOOL freerdp_client_parse_rdp_file_buffer_ex(rdpFile* file, const BYTE* buffer,
|
||||
if ((buffer[0] == BOM_UTF16_LE[0]) && (buffer[1] == BOM_UTF16_LE[1]))
|
||||
{
|
||||
LPCWSTR uc = (LPCWSTR)(&buffer[2]);
|
||||
- size = size / sizeof(WCHAR) - 1;
|
||||
-
|
||||
- copy = ConvertWCharNToUtf8Alloc(uc, size, NULL);
|
||||
+ const size_t charlen = size / sizeof(WCHAR) - 1;
|
||||
+ copy = ConvertWCharNToUtf8Alloc(uc, charlen, &size);
|
||||
if (!copy)
|
||||
{
|
||||
WLog_ERR(TAG, "Failed to convert RDP file from UCS2 to UTF8");
|
||||
@@ -926,65 +963,16 @@ BOOL freerdp_client_parse_rdp_file_buffer_ex(rdpFile* file, const BYTE* buffer,
|
||||
memcpy(copy, buffer, size);
|
||||
}
|
||||
|
||||
- line = strtok_s(copy, "\r\n", &context);
|
||||
+ char* context = NULL;
|
||||
+ char* line = strtok_s(copy, "\r\n", &context);
|
||||
|
||||
while (line)
|
||||
{
|
||||
- length = strnlen(line, size);
|
||||
-
|
||||
- if (length > 1)
|
||||
- {
|
||||
- beg = line;
|
||||
- if (beg[0] == '/')
|
||||
- {
|
||||
- if (!freerdp_client_parse_rdp_file_option(file, line))
|
||||
- goto fail;
|
||||
-
|
||||
- goto next_line; /* FreeRDP option */
|
||||
- }
|
||||
-
|
||||
- d1 = strchr(line, ':');
|
||||
-
|
||||
- if (!d1)
|
||||
- goto next_line; /* not first delimiter */
|
||||
+ const size_t length = strnlen(line, size);
|
||||
|
||||
- type = &d1[1];
|
||||
- d2 = strchr(type, ':');
|
||||
-
|
||||
- if (!d2)
|
||||
- goto next_line; /* no second delimiter */
|
||||
-
|
||||
- if ((d2 - d1) != 2)
|
||||
- goto next_line; /* improper type length */
|
||||
-
|
||||
- *d1 = 0;
|
||||
- *d2 = 0;
|
||||
- name = beg;
|
||||
- value = &d2[1];
|
||||
-
|
||||
- if (parse && parse(file->context, name, *type, value))
|
||||
- {
|
||||
- }
|
||||
- else if (*type == 'i')
|
||||
- {
|
||||
- /* integer type */
|
||||
- if (!freerdp_client_parse_rdp_file_integer(file, name, value))
|
||||
- goto fail;
|
||||
- }
|
||||
- else if (*type == 's')
|
||||
- {
|
||||
- /* string type */
|
||||
- if (!freerdp_client_parse_rdp_file_string(file, name, value))
|
||||
- goto fail;
|
||||
- }
|
||||
- else if (*type == 'b')
|
||||
- {
|
||||
- /* binary type */
|
||||
- WLog_ERR(TAG, "Unsupported RDP file binary option %s [value=%s]", name, value);
|
||||
- }
|
||||
- }
|
||||
+ if (!parse_line(file, line, length, parse))
|
||||
+ goto fail;
|
||||
|
||||
- next_line:
|
||||
line = strtok_s(NULL, "\r\n", &context);
|
||||
}
|
||||
|
||||
21
client-common-fix-double-free.patch
Normal file
21
client-common-fix-double-free.patch
Normal file
@ -0,0 +1,21 @@
|
||||
From 005c5abacbb569f0f66deee710e1f1a87794f368 Mon Sep 17 00:00:00 2001
|
||||
From: Armin Novak <armin.novak@thincast.com>
|
||||
Date: Wed, 1 Jul 2026 23:03:29 +0200
|
||||
Subject: [PATCH] [client,common] fix double free
|
||||
|
||||
---
|
||||
client/common/file.c | 1 -
|
||||
1 file changed, 1 deletion(-)
|
||||
|
||||
diff --git a/client/common/file.c b/client/common/file.c
|
||||
index 35e8643f2..606aab0f7 100644
|
||||
--- a/client/common/file.c
|
||||
+++ b/client/common/file.c
|
||||
@@ -2457,7 +2457,6 @@ BOOL freerdp_client_populate_settings_from_rdp_file(const rdpFile* file, rdpSett
|
||||
if ((val >= UINT32_MAX) && (errno != 0))
|
||||
{
|
||||
CommandLineParserFree(ptr);
|
||||
- free(list);
|
||||
return FALSE;
|
||||
}
|
||||
list[x] = (UINT32)val;
|
||||
60
core-message-fix-update_message_WindowIcon.patch
Normal file
60
core-message-fix-update_message_WindowIcon.patch
Normal file
@ -0,0 +1,60 @@
|
||||
From 5bf8d59e880336d5a22d7f40e3bb1d74dc81d87b Mon Sep 17 00:00:00 2001
|
||||
From: Armin Novak <armin.novak@thincast.com>
|
||||
Date: Tue, 7 Jul 2026 12:58:11 +0200
|
||||
Subject: [PATCH] [core,message] fix update_message_WindowIcon
|
||||
|
||||
---
|
||||
libfreerdp/core/message.c | 17 ++++++++---------
|
||||
1 file changed, 8 insertions(+), 9 deletions(-)
|
||||
|
||||
diff --git a/libfreerdp/core/message.c b/libfreerdp/core/message.c
|
||||
index 73961a026..a3f376026 100644
|
||||
--- a/libfreerdp/core/message.c
|
||||
+++ b/libfreerdp/core/message.c
|
||||
@@ -1293,30 +1293,29 @@ static BOOL update_message_WindowUpdate(rdpContext* context, const WINDOW_ORDER_
|
||||
static BOOL update_message_WindowIcon(rdpContext* context, const WINDOW_ORDER_INFO* orderInfo,
|
||||
const WINDOW_ICON_ORDER* windowIcon)
|
||||
{
|
||||
- WINDOW_ORDER_INFO* wParam = NULL;
|
||||
- WINDOW_ICON_ORDER* lParam = NULL;
|
||||
- rdp_update_internal* up = NULL;
|
||||
-
|
||||
if (!context || !context->update || !orderInfo || !windowIcon)
|
||||
return FALSE;
|
||||
|
||||
- wParam = (WINDOW_ORDER_INFO*)malloc(sizeof(WINDOW_ORDER_INFO));
|
||||
+ WINDOW_ORDER_INFO* wParam = (WINDOW_ORDER_INFO*)malloc(sizeof(WINDOW_ORDER_INFO));
|
||||
|
||||
if (!wParam)
|
||||
return FALSE;
|
||||
|
||||
- CopyMemory(wParam, orderInfo, sizeof(WINDOW_ORDER_INFO));
|
||||
- lParam = (WINDOW_ICON_ORDER*)calloc(1, sizeof(WINDOW_ICON_ORDER));
|
||||
+ *wParam = *orderInfo;
|
||||
+
|
||||
+ WINDOW_ICON_ORDER* lParam = (WINDOW_ICON_ORDER*)calloc(1, sizeof(WINDOW_ICON_ORDER));
|
||||
|
||||
if (!lParam)
|
||||
goto out_fail;
|
||||
|
||||
+ *lParam = *windowIcon;
|
||||
lParam->iconInfo = calloc(1, sizeof(ICON_INFO));
|
||||
|
||||
if (!lParam->iconInfo)
|
||||
goto out_fail;
|
||||
|
||||
- CopyMemory(lParam, windowIcon, sizeof(WINDOW_ICON_ORDER));
|
||||
+ *lParam->iconInfo = *windowIcon->iconInfo;
|
||||
+
|
||||
WLog_VRB(TAG, "update_message_WindowIcon");
|
||||
|
||||
if (windowIcon->iconInfo->cbBitsColor > 0)
|
||||
@@ -1352,7 +1351,7 @@ static BOOL update_message_WindowIcon(rdpContext* context, const WINDOW_ORDER_IN
|
||||
windowIcon->iconInfo->cbColorTable);
|
||||
}
|
||||
|
||||
- up = update_cast(context->update);
|
||||
+ rdp_update_internal* up = update_cast(context->update);
|
||||
return MessageQueue_Post(up->queue, (void*)context, MakeMessageId(WindowUpdate, WindowIcon),
|
||||
(void*)wParam, (void*)lParam);
|
||||
out_fail:
|
||||
201
core-redirection-check-redirection-values-for-validity.patch
Normal file
201
core-redirection-check-redirection-values-for-validity.patch
Normal file
@ -0,0 +1,201 @@
|
||||
From 81747fa9100fdb3fde2aae71cda2a79c82f6e363 Mon Sep 17 00:00:00 2001
|
||||
From: Armin Novak <armin.novak@thincast.com>
|
||||
Date: Thu, 9 Jul 2026 08:34:24 +0200
|
||||
Subject: [PATCH] [core,redirection] check redirection values for validity
|
||||
|
||||
Add some basic validity checks for data provided by server.
|
||||
---
|
||||
libfreerdp/core/gateway/arm.c | 11 +++++++++++
|
||||
libfreerdp/core/redirection.c | 25 ++++++++++++++++++++-----
|
||||
libfreerdp/core/utils.c | 26 ++++++++++++++++++++++++++
|
||||
libfreerdp/core/utils.h | 2 ++
|
||||
4 files changed, 59 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/libfreerdp/core/gateway/arm.c b/libfreerdp/core/gateway/arm.c
|
||||
index 4433f6ac9..0e82cf775 100644
|
||||
--- a/libfreerdp/core/gateway/arm.c
|
||||
+++ b/libfreerdp/core/gateway/arm.c
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <winpr/assert.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
+#include <winpr/string.h>
|
||||
#include <winpr/synch.h>
|
||||
#include <winpr/print.h>
|
||||
#include <winpr/stream.h>
|
||||
@@ -654,6 +655,10 @@ static BOOL arm_parse_ipv6(rdpSettings* settings, WINPR_JSON* ipv6, size_t* pAdd
|
||||
const char* addr = WINPR_JSON_GetStringValue(adressN);
|
||||
if (utils_str_is_empty(addr))
|
||||
continue;
|
||||
+
|
||||
+ if (!winpr_str_is_valid_url(addr))
|
||||
+ return FALSE;
|
||||
+
|
||||
if (!freerdp_settings_set_pointer_array(settings, FreeRDP_TargetNetAddresses,
|
||||
(*pAddressIdx)++, addr))
|
||||
return FALSE;
|
||||
@@ -684,6 +689,9 @@ static BOOL arm_parse_ipv4(rdpSettings* settings, WINPR_JSON* ipv4, size_t* pAdd
|
||||
const char* publicIp = WINPR_JSON_GetStringValue(publicIpNode);
|
||||
if (!utils_str_is_empty(publicIp))
|
||||
{
|
||||
+ if (!utils_is_valid_ip(publicIp))
|
||||
+ return FALSE;
|
||||
+
|
||||
if (!freerdp_settings_set_pointer_array(settings, FreeRDP_TargetNetAddresses,
|
||||
(*pAddressIdx)++, publicIp))
|
||||
return FALSE;
|
||||
@@ -696,6 +704,9 @@ static BOOL arm_parse_ipv4(rdpSettings* settings, WINPR_JSON* ipv4, size_t* pAdd
|
||||
const char* privateIp = WINPR_JSON_GetStringValue(privateIpNode);
|
||||
if (!utils_str_is_empty(privateIp))
|
||||
{
|
||||
+ if (!utils_is_valid_ip(privateIp))
|
||||
+ return FALSE;
|
||||
+
|
||||
if (!freerdp_settings_set_pointer_array(settings, FreeRDP_TargetNetAddresses,
|
||||
(*pAddressIdx)++, privateIp))
|
||||
return FALSE;
|
||||
diff --git a/libfreerdp/core/redirection.c b/libfreerdp/core/redirection.c
|
||||
index 286976929..6f7dcdb57 100644
|
||||
--- a/libfreerdp/core/redirection.c
|
||||
+++ b/libfreerdp/core/redirection.c
|
||||
@@ -699,6 +699,8 @@ static state_run_t rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s)
|
||||
{
|
||||
if (!rdp_redirection_read_unicode_string(s, &(redirection->TargetNetAddress), 80))
|
||||
return STATE_RUN_FAILED;
|
||||
+ if (!utils_is_valid_ip(redirection->TargetNetAddress))
|
||||
+ return STATE_RUN_FAILED;
|
||||
}
|
||||
|
||||
if (redirection->flags & LB_LOAD_BALANCE_INFO)
|
||||
@@ -712,13 +714,17 @@ static state_run_t rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s)
|
||||
if (!rdp_redirection_read_data(LB_LOAD_BALANCE_INFO, s, &redirection->LoadBalanceInfoLength,
|
||||
&redirection->LoadBalanceInfo))
|
||||
return STATE_RUN_FAILED;
|
||||
+ if (!winpr_str_is_valid_urlN((const char*)redirection->LoadBalanceInfo,
|
||||
+ redirection->LoadBalanceInfoLength))
|
||||
+ return STATE_RUN_FAILED;
|
||||
}
|
||||
|
||||
if (redirection->flags & LB_USERNAME)
|
||||
{
|
||||
if (!rdp_redirection_read_unicode_string(s, &(redirection->Username), 512))
|
||||
return STATE_RUN_FAILED;
|
||||
-
|
||||
+ if (winpr_str_has_newlines(redirection->Username))
|
||||
+ return STATE_RUN_FAILED;
|
||||
WLog_DBG(TAG, "Username: %s", redirection->Username);
|
||||
}
|
||||
|
||||
@@ -726,7 +732,8 @@ static state_run_t rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s)
|
||||
{
|
||||
if (!rdp_redirection_read_unicode_string(s, &(redirection->Domain), 52))
|
||||
return STATE_RUN_FAILED;
|
||||
-
|
||||
+ if (winpr_str_has_newlines(redirection->Domain))
|
||||
+ return STATE_RUN_FAILED;
|
||||
WLog_DBG(TAG, "Domain: %s", redirection->Domain);
|
||||
}
|
||||
|
||||
@@ -784,7 +791,8 @@ static state_run_t rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s)
|
||||
{
|
||||
if (!rdp_redirection_read_unicode_string(s, &(redirection->TargetFQDN), 512))
|
||||
return STATE_RUN_FAILED;
|
||||
-
|
||||
+ if (!winpr_str_is_valid_url(redirection->TargetFQDN))
|
||||
+ return STATE_RUN_FAILED;
|
||||
WLog_DBG(TAG, "TargetFQDN: %s", redirection->TargetFQDN);
|
||||
}
|
||||
|
||||
@@ -792,7 +800,8 @@ static state_run_t rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s)
|
||||
{
|
||||
if (!rdp_redirection_read_unicode_string(s, &(redirection->TargetNetBiosName), 32))
|
||||
return STATE_RUN_FAILED;
|
||||
-
|
||||
+ if (!winpr_str_is_valid_url(redirection->TargetNetBiosName))
|
||||
+ return STATE_RUN_FAILED;
|
||||
WLog_DBG(TAG, "TargetNetBiosName: %s", redirection->TargetNetBiosName);
|
||||
}
|
||||
|
||||
@@ -801,6 +810,8 @@ static state_run_t rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s)
|
||||
if (!rdp_redirection_read_data(LB_CLIENT_TSV_URL, s, &redirection->TsvUrlLength,
|
||||
&redirection->TsvUrl))
|
||||
return STATE_RUN_FAILED;
|
||||
+ if (!winpr_str_is_valid_urlN((const char*)redirection->TsvUrl, redirection->TsvUrlLength))
|
||||
+ return STATE_RUN_FAILED;
|
||||
}
|
||||
|
||||
if (redirection->flags & LB_REDIRECTION_GUID)
|
||||
@@ -862,7 +873,8 @@ static state_run_t rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s)
|
||||
{
|
||||
if (!rdp_redirection_read_unicode_string(s, &(redirection->TargetNetAddresses[i]), 80))
|
||||
return STATE_RUN_FAILED;
|
||||
-
|
||||
+ if (!utils_is_valid_ip(redirection->TargetNetAddresses[i]))
|
||||
+ return STATE_RUN_FAILED;
|
||||
WLog_DBG(TAG, "TargetNetAddresses[%" PRIu32 "]: %s", i,
|
||||
redirection->TargetNetAddresses[i]);
|
||||
}
|
||||
@@ -890,7 +902,10 @@ state_run_t rdp_recv_enhanced_security_redirection_packet(rdpRdp* rdp, wStream*
|
||||
status = rdp_recv_server_redirection_pdu(rdp, s);
|
||||
|
||||
if (state_run_failed(status))
|
||||
+ {
|
||||
+ WLog_Print(rdp->log, WLOG_ERROR, "redirection packet invalid, aborting");
|
||||
return status;
|
||||
+ }
|
||||
|
||||
if (Stream_GetRemainingLength(s) >= 1)
|
||||
{
|
||||
diff --git a/libfreerdp/core/utils.c b/libfreerdp/core/utils.c
|
||||
index 0f395d893..c46c21e23 100644
|
||||
--- a/libfreerdp/core/utils.c
|
||||
+++ b/libfreerdp/core/utils.c
|
||||
@@ -28,6 +28,13 @@
|
||||
#include <freerdp/channels/cliprdr.h>
|
||||
#include <freerdp/channels/rdpdr.h>
|
||||
|
||||
+#ifdef _WIN32
|
||||
+#include <winsock2.h>
|
||||
+#include <ws2tcpip.h>
|
||||
+#else
|
||||
+#include <arpa/inet.h>
|
||||
+#endif
|
||||
+
|
||||
#include <freerdp/log.h>
|
||||
#define TAG FREERDP_TAG("core.gateway.utils")
|
||||
|
||||
@@ -480,3 +487,22 @@ BOOL utils_reload_channels(rdpContext* context)
|
||||
return freerdp_channels_pre_connect(context->channels, context->instance) == CHANNEL_RC_OK;
|
||||
return rc;
|
||||
}
|
||||
+
|
||||
+static BOOL isValidIPv4(const char* ipAddress)
|
||||
+{
|
||||
+ struct sockaddr_in sa = { 0 };
|
||||
+ int result = inet_pton(AF_INET, ipAddress, &(sa.sin_addr));
|
||||
+ return result != 0;
|
||||
+}
|
||||
+
|
||||
+static BOOL isValidIPv6(const char* ipAddress)
|
||||
+{
|
||||
+ struct sockaddr_in6 sa = { 0 };
|
||||
+ int result = inet_pton(AF_INET6, ipAddress, &(sa.sin6_addr));
|
||||
+ return result != 0;
|
||||
+}
|
||||
+
|
||||
+BOOL utils_is_valid_ip(const char* ipAddress)
|
||||
+{
|
||||
+ return isValidIPv4(ipAddress) || isValidIPv6(ipAddress);
|
||||
+}
|
||||
diff --git a/libfreerdp/core/utils.h b/libfreerdp/core/utils.h
|
||||
index a42dcad94..6b25c580c 100644
|
||||
--- a/libfreerdp/core/utils.h
|
||||
+++ b/libfreerdp/core/utils.h
|
||||
@@ -61,4 +61,6 @@ char* utils_redir_flags_to_string(UINT32 flags, char* buffer, size_t size);
|
||||
|
||||
BOOL utils_reload_channels(rdpContext* context);
|
||||
|
||||
+FREERDP_LOCAL BOOL utils_is_valid_ip(const char* ipAddress);
|
||||
+
|
||||
#endif /* FREERDP_LIB_CORE_UTILS_H */
|
||||
|
||||
34
core-redirection-relax-checks.patch
Normal file
34
core-redirection-relax-checks.patch
Normal file
@ -0,0 +1,34 @@
|
||||
From 1c4b028928be8f38e968d8bfb7d3fb6864540b42 Mon Sep 17 00:00:00 2001
|
||||
From: Armin Novak <armin.novak@thincast.com>
|
||||
Date: Tue, 14 Jul 2026 12:30:27 +0200
|
||||
Subject: [PATCH] [core,redirection] relax checks
|
||||
|
||||
* TsvUrl is opaque, do not assume any format
|
||||
* LoadBalanceInfo is opaque, do not assume any format
|
||||
---
|
||||
libfreerdp/core/redirection.c | 5 -----
|
||||
1 file changed, 5 deletions(-)
|
||||
|
||||
diff --git a/libfreerdp/core/redirection.c b/libfreerdp/core/redirection.c
|
||||
index 6f7dcdb57..f9690567d 100644
|
||||
--- a/libfreerdp/core/redirection.c
|
||||
+++ b/libfreerdp/core/redirection.c
|
||||
@@ -714,9 +714,6 @@ static state_run_t rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s)
|
||||
if (!rdp_redirection_read_data(LB_LOAD_BALANCE_INFO, s, &redirection->LoadBalanceInfoLength,
|
||||
&redirection->LoadBalanceInfo))
|
||||
return STATE_RUN_FAILED;
|
||||
- if (!winpr_str_is_valid_urlN((const char*)redirection->LoadBalanceInfo,
|
||||
- redirection->LoadBalanceInfoLength))
|
||||
- return STATE_RUN_FAILED;
|
||||
}
|
||||
|
||||
if (redirection->flags & LB_USERNAME)
|
||||
@@ -810,8 +807,6 @@ static state_run_t rdp_recv_server_redirection_pdu(rdpRdp* rdp, wStream* s)
|
||||
if (!rdp_redirection_read_data(LB_CLIENT_TSV_URL, s, &redirection->TsvUrlLength,
|
||||
&redirection->TsvUrl))
|
||||
return STATE_RUN_FAILED;
|
||||
- if (!winpr_str_is_valid_urlN((const char*)redirection->TsvUrl, redirection->TsvUrlLength))
|
||||
- return STATE_RUN_FAILED;
|
||||
}
|
||||
|
||||
if (redirection->flags & LB_REDIRECTION_GUID)
|
||||
31
crypto-fix-out-buffer-check.patch
Normal file
31
crypto-fix-out-buffer-check.patch
Normal file
@ -0,0 +1,31 @@
|
||||
From 86472e2d967e0b211eeb0405955ba146c7a97f5f Mon Sep 17 00:00:00 2001
|
||||
From: Armin Novak <armin.novak@thincast.com>
|
||||
Date: Thu, 2 Jul 2026 08:02:26 +0200
|
||||
Subject: [PATCH] [crypto] fix out buffer check
|
||||
|
||||
---
|
||||
libfreerdp/crypto/crypto.c | 9 ++++++---
|
||||
1 file changed, 6 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/libfreerdp/crypto/crypto.c b/libfreerdp/crypto/crypto.c
|
||||
index 806f9b986..e6f156494 100644
|
||||
--- a/libfreerdp/crypto/crypto.c
|
||||
+++ b/libfreerdp/crypto/crypto.c
|
||||
@@ -103,11 +103,14 @@ static SSIZE_T crypto_rsa_common(const BYTE* input, size_t length, UINT32 key_le
|
||||
goto fail;
|
||||
if (BN_mod_exp(y, x, exp, mod, ctx) != 1)
|
||||
goto fail;
|
||||
- output_length = BN_bn2bin(y, output);
|
||||
+ {
|
||||
+ const int len = BN_num_bytes(y);
|
||||
+ if ((len < 0) || ((size_t)len > out_length))
|
||||
+ goto fail;
|
||||
+ output_length = BN_bn2bin(y, output);
|
||||
+ }
|
||||
if (output_length < 0)
|
||||
goto fail;
|
||||
- if ((size_t)output_length > out_length)
|
||||
- goto fail;
|
||||
crypto_reverse(output, output_length);
|
||||
|
||||
if ((size_t)output_length < key_length)
|
||||
40
freerdp.spec
40
freerdp.spec
@ -30,7 +30,7 @@
|
||||
Name: freerdp
|
||||
Epoch: 2
|
||||
Version: 3.10.3
|
||||
Release: 12%{?dist}.7
|
||||
Release: 12%{?dist}.8
|
||||
Summary: Free implementation of the Remote Desktop Protocol (RDP)
|
||||
|
||||
# The effective license is Apache-2.0 but:
|
||||
@ -277,6 +277,38 @@ Patch: channels-rdpear-disable-ndr-pointer-aliasing.patch
|
||||
Patch: core-orders-add-codecID-checks.patch
|
||||
Patch: gdi-graphics-fix-gdi_Bitmap_Decompress.patch
|
||||
|
||||
# CVE-2026-64624
|
||||
# https://github.com/FreeRDP/FreeRDP/commit/e551807abfb87a8a1890c8b7e36fe421cd5596be
|
||||
# https://github.com/FreeRDP/FreeRDP/commit/22c5deea52404f51a13276b3abda44e1e60704cf
|
||||
Patch: client-common-deprecate-cli-options-in-rdp-files.patch
|
||||
Patch: client-common-deactivate-cli-parsing-in-rdp-files.patch
|
||||
|
||||
# CVE-2026-64621
|
||||
# https://github.com/FreeRDP/FreeRDP/commit/7696267929ae8ba045c1bbe275b3915653828313
|
||||
Patch: client-common-fix-double-free.patch
|
||||
|
||||
# CVE-2026-64620
|
||||
# https://github.com/FreeRDP/FreeRDP/commit/27014741a8c22a34d3040c559c82f4ed82841bef
|
||||
Patch: crypto-fix-out-buffer-check.patch
|
||||
|
||||
# CVE-2026-68580
|
||||
# https://github.com/FreeRDP/FreeRDP/commit/3bf07d4470bbe42faf4ef8197c8fe1b6b759b00f
|
||||
# https://github.com/FreeRDP/FreeRDP/commit/9ca0aa69c4679b2be274ac59f30e76d0fa81aaf4
|
||||
Patch: channels-audin-limit-FramesPerPacket.patch
|
||||
Patch: channels-audin-tighten-parameter-checks.patch
|
||||
|
||||
# CVE-2026-67299
|
||||
# https://github.com/FreeRDP/FreeRDP/commit/172edbddd24f33033b9eafae6ea1fff0641a24f4
|
||||
Patch: core-message-fix-update_message_WindowIcon.patch
|
||||
|
||||
# CVE-2026-67289
|
||||
# https://github.com/FreeRDP/FreeRDP/commit/f163b2d2080d922cb725800781f43f16bc2882c0
|
||||
# https://github.com/FreeRDP/FreeRDP/commit/ab5905cbada0d34cf85ffd32881cacaf8275744f
|
||||
# https://github.com/FreeRDP/FreeRDP/commit/1db16b4b121a1221c0454f7d223096cac87bf244
|
||||
Patch: winpr-crt-add-functions-to-test-string.patch
|
||||
Patch: core-redirection-check-redirection-values-for-validity.patch
|
||||
Patch: core-redirection-relax-checks.patch
|
||||
|
||||
BuildRequires: gcc
|
||||
BuildRequires: gcc-c++
|
||||
BuildRequires: alsa-lib-devel
|
||||
@ -600,6 +632,12 @@ find %{buildroot} -name "*.a" -delete
|
||||
%{_libdir}/pkgconfig/winpr-tools3.pc
|
||||
|
||||
%changelog
|
||||
* Tue Aug 04 2026 RHEL Packaging Agent <redhat-ymir-agent@redhat.com> - 2:3.10.3-12.8
|
||||
- Backport several CVE fixes (CVE-2026-64620, CVE-2026-64621, CVE-2026-64624,
|
||||
CVE-2026-67289, CVE-2026-67299, CVE-2026-68580)
|
||||
Resolves: RHEL-212621, RHEL-212978, RHEL-213168, RHEL-222783, RHEL-222983,
|
||||
Resolves: RHEL-223604
|
||||
|
||||
* Sat Jul 11 2026 RHEL Packaging Agent <redhat-ymir-agent@redhat.com> - 2:3.10.3-12.7
|
||||
- Add codecID checks for CACHE_BITMAP_V3_ORDER (CVE-2026-55827)
|
||||
- Fix boundary checks in gdi_Bitmap_Decompress (CVE-2026-55827)
|
||||
|
||||
313
winpr-crt-add-functions-to-test-string.patch
Normal file
313
winpr-crt-add-functions-to-test-string.patch
Normal file
@ -0,0 +1,313 @@
|
||||
From 65d51c15af42a4d6cce83eac416fa25af0c2ca93 Mon Sep 17 00:00:00 2001
|
||||
From: Armin Novak <armin.novak@thincast.com>
|
||||
Date: Thu, 9 Jul 2026 08:34:23 +0200
|
||||
Subject: [PATCH] [winpr,crt] add functions to test string
|
||||
|
||||
* winpr_str_has_newlines to check for newlines in a string
|
||||
* winpr_str_is_valid_url and winpr_str_is_valid_urlN to check if a
|
||||
string is a valid url
|
||||
---
|
||||
winpr/include/winpr/string.h | 25 ++++++
|
||||
winpr/libwinpr/crt/CMakeLists.txt | 8 ++
|
||||
winpr/libwinpr/crt/string.c | 115 +++++++++++++++++++++++++++
|
||||
winpr/libwinpr/crt/test/TestString.c | 80 +++++++++++++++++++
|
||||
4 files changed, 228 insertions(+)
|
||||
|
||||
diff --git a/winpr/include/winpr/string.h b/winpr/include/winpr/string.h
|
||||
index 45a4098cc..0821293ec 100644
|
||||
--- a/winpr/include/winpr/string.h
|
||||
+++ b/winpr/include/winpr/string.h
|
||||
@@ -39,6 +39,31 @@ extern "C"
|
||||
WINPR_API char* winpr_str_url_encode(const char* str, size_t len);
|
||||
WINPR_API char* winpr_str_url_decode(const char* str, size_t len);
|
||||
|
||||
+ /** @brief checks if a string is a valid URL
|
||||
+ *
|
||||
+ * @param str The string to check
|
||||
+ * @return \b TRUE if valid, \b FALSE otherwise
|
||||
+ * @since version 3.29.0
|
||||
+ */
|
||||
+ WINPR_API BOOL winpr_str_is_valid_url(const char* str);
|
||||
+
|
||||
+ /** @brief checks if a string is a valid URL
|
||||
+ *
|
||||
+ * @param str The string to check
|
||||
+ * @param len The length of the string in bytes
|
||||
+ * @return \b TRUE if valid, \b FALSE otherwise
|
||||
+ * @since version 3.29.0
|
||||
+ */
|
||||
+ WINPR_API BOOL winpr_str_is_valid_urlN(const char* str, size_t len);
|
||||
+
|
||||
+ /** @brief checks if a string contains newlines
|
||||
+ *
|
||||
+ * @param str The string to check
|
||||
+ * @return \b TRUE if it has newlines, \b FALSE otherwise
|
||||
+ * @since version 3.29.0
|
||||
+ */
|
||||
+ WINPR_API BOOL winpr_str_has_newlines(const char* str);
|
||||
+
|
||||
WINPR_API BOOL winpr_str_append(const char* what, char* buffer, size_t size,
|
||||
const char* separator);
|
||||
|
||||
diff --git a/winpr/libwinpr/crt/CMakeLists.txt b/winpr/libwinpr/crt/CMakeLists.txt
|
||||
index 18f6ad139..b2cc1cf94 100644
|
||||
--- a/winpr/libwinpr/crt/CMakeLists.txt
|
||||
+++ b/winpr/libwinpr/crt/CMakeLists.txt
|
||||
@@ -17,6 +17,14 @@
|
||||
|
||||
set(CRT_FILES alignment.c conversion.c buffer.c memory.c unicode.c string.c)
|
||||
|
||||
+include(CheckSymbolExists)
|
||||
+check_symbol_exists(regcomp regex.h WINPR_HAVE_REGCOMP)
|
||||
+check_symbol_exists(regexec regex.h WINPR_HAVE_REGEXEC)
|
||||
+check_symbol_exists(regfree regex.h WINPR_HAVE_REGFREE)
|
||||
+if(WINPR_HAVE_REGCOMP AND WINPR_HAVE_REGEXEC AND WINPR_HAVE_REGFREE)
|
||||
+ winpr_definition_add(WINPR_HAVE_REGCOMP)
|
||||
+endif()
|
||||
+
|
||||
if(WITH_UNICODE_BUILTIN)
|
||||
list(APPEND CRT_FILES unicode_builtin.c)
|
||||
else()
|
||||
diff --git a/winpr/libwinpr/crt/string.c b/winpr/libwinpr/crt/string.c
|
||||
index 4dec0b141..b78bbdc2e 100644
|
||||
--- a/winpr/libwinpr/crt/string.c
|
||||
+++ b/winpr/libwinpr/crt/string.c
|
||||
@@ -33,6 +33,10 @@
|
||||
#include <uriparser/Uri.h>
|
||||
#endif
|
||||
|
||||
+#if defined(WINPR_HAVE_REGCOMP)
|
||||
+#include <regex.h>
|
||||
+#endif
|
||||
+
|
||||
/* String Manipulation (CRT): http://msdn.microsoft.com/en-us/library/f0151s4x.aspx */
|
||||
|
||||
#include "../log.h"
|
||||
@@ -43,6 +47,28 @@
|
||||
#endif
|
||||
|
||||
#if defined(WITH_URIPARSER)
|
||||
+BOOL winpr_str_is_valid_urlN(const char* str, size_t len)
|
||||
+{
|
||||
+ if (!str || (len == 0))
|
||||
+ return FALSE;
|
||||
+
|
||||
+ const char* errorPos = NULL;
|
||||
+ UriUriA uri = { 0 };
|
||||
+ const int rc = uriParseSingleUriExA(&uri, str, &str[len - 1], &errorPos);
|
||||
+ return rc == URI_SUCCESS;
|
||||
+}
|
||||
+
|
||||
+BOOL winpr_str_is_valid_url(const char* str)
|
||||
+{
|
||||
+ if (!str)
|
||||
+ return FALSE;
|
||||
+
|
||||
+ const char* errorPos = NULL;
|
||||
+ UriUriA uri = { 0 };
|
||||
+ const int rc = uriParseSingleUriA(&uri, str, &errorPos);
|
||||
+ return rc == URI_SUCCESS;
|
||||
+}
|
||||
+
|
||||
char* winpr_str_url_decode(const char* str, size_t len)
|
||||
{
|
||||
char* dst = strndup(str, len);
|
||||
@@ -155,6 +181,59 @@ char* winpr_str_url_encode(const char* str, size_t len)
|
||||
}
|
||||
return dst;
|
||||
}
|
||||
+
|
||||
+BOOL winpr_str_is_valid_urlN(const char* str, size_t len)
|
||||
+{
|
||||
+ if (!str || (len == 0))
|
||||
+ return FALSE;
|
||||
+
|
||||
+ char* url = strndup(str, len);
|
||||
+ if (!url)
|
||||
+ return FALSE;
|
||||
+
|
||||
+ const BOOL rc = winpr_str_is_valid_url(url);
|
||||
+ free(url);
|
||||
+ return rc;
|
||||
+}
|
||||
+
|
||||
+#if defined(_WIN32)
|
||||
+#include <shlwapi.h>
|
||||
+
|
||||
+BOOL winpr_str_is_valid_url(const char* str)
|
||||
+{
|
||||
+ if (!str)
|
||||
+ return FALSE;
|
||||
+ return PathIsURLA(str);
|
||||
+}
|
||||
+
|
||||
+#elif defined(WINPR_HAVE_REGCOMP)
|
||||
+BOOL winpr_str_is_valid_url(const char* str)
|
||||
+{
|
||||
+ if (!str)
|
||||
+ return FALSE;
|
||||
+ regex_t regex = { 0 };
|
||||
+ const char pattern[] = "^([a-z]+://)?([a-zA-Z0-9.-]+)(:[0-9]+)?(/[a-zA-Z0-9./?=&%-]*)?$";
|
||||
+
|
||||
+ int ret = regcomp(®ex, pattern, REG_EXTENDED);
|
||||
+ if (ret)
|
||||
+ {
|
||||
+ printf("Could not compile regex\n");
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+
|
||||
+ ret = regexec(®ex, str, 0, NULL, 0);
|
||||
+ regfree(®ex);
|
||||
+ return ret == 0;
|
||||
+}
|
||||
+
|
||||
+#else
|
||||
+BOOL winpr_str_is_valid_url(WINPR_ATTR_UNUSED const char* str)
|
||||
+{
|
||||
+ WLog_WARN(TAG, "URL validation not supported by your build, not performing check. Build with "
|
||||
+ "-DWITH_URIPARSER=ON to fix.");
|
||||
+ return TRUE;
|
||||
+}
|
||||
+#endif
|
||||
#endif
|
||||
|
||||
BOOL winpr_str_append(const char* what, char* buffer, size_t size, const char* separator)
|
||||
@@ -845,3 +924,39 @@ WCHAR* wcsndup(const WCHAR* s, size_t n)
|
||||
memcpy(copy, s, n * sizeof(WCHAR));
|
||||
return copy;
|
||||
}
|
||||
+
|
||||
+BOOL winpr_str_has_newlines(const char* str)
|
||||
+{
|
||||
+ if (!str)
|
||||
+ return FALSE;
|
||||
+ do
|
||||
+ {
|
||||
+ char c = *str++;
|
||||
+ switch (c)
|
||||
+ {
|
||||
+ case '\r':
|
||||
+ case '\n':
|
||||
+ case 0x0b: /* VT vertical tab */
|
||||
+ case 0x0c: /* FF form feed */
|
||||
+ case (char)0x85: /* NEL next line */
|
||||
+ return TRUE;
|
||||
+ case 0x20:
|
||||
+ {
|
||||
+ switch (*str)
|
||||
+ {
|
||||
+ case 0x28: /* LS line separator */
|
||||
+ case 0x29: /* PS paragraph separator */
|
||||
+ return TRUE;
|
||||
+ default:
|
||||
+ break;
|
||||
+ }
|
||||
+ }
|
||||
+ break;
|
||||
+
|
||||
+ case '\0':
|
||||
+ return FALSE;
|
||||
+ default:
|
||||
+ break;
|
||||
+ }
|
||||
+ } while (1);
|
||||
+}
|
||||
diff --git a/winpr/libwinpr/crt/test/TestString.c b/winpr/libwinpr/crt/test/TestString.c
|
||||
index e77bf02da..0ab06ab78 100644
|
||||
--- a/winpr/libwinpr/crt/test/TestString.c
|
||||
+++ b/winpr/libwinpr/crt/test/TestString.c
|
||||
@@ -104,6 +104,80 @@ fail:
|
||||
return rc;
|
||||
}
|
||||
|
||||
+
|
||||
+static BOOL test_valid_url(void)
|
||||
+{
|
||||
+ struct test_t
|
||||
+ {
|
||||
+ char* string;
|
||||
+ size_t len;
|
||||
+ BOOL isUrl;
|
||||
+ };
|
||||
+
|
||||
+ static const struct test_t tests[] = { { "foo.bar.blabla", 15, TRUE },
|
||||
+ { "somehostname", 12, TRUE },
|
||||
+ { "somehostname:1234", 17, TRUE },
|
||||
+ { "tsv://somehostname", 18, TRUE },
|
||||
+ { "tsv://somehostname/path/foo/gaga", 32, TRUE },
|
||||
+ { "tsv://somehostname:1234", 23, TRUE },
|
||||
+ { "tsv://somehostname:1234/path/foo", 33, TRUE },
|
||||
+ { "lala\rgaga\n", 12, FALSE },
|
||||
+ { "192.168.0.1", 11, TRUE },
|
||||
+ //{ "192.168.0.1:1234", 16, FALSE },
|
||||
+ //{ "192.168.0.1:1234/foo/", 21, FALSE },
|
||||
+ { "192.168.0.1/bar/foo/", 20, TRUE },
|
||||
+ { "[::1]", 5, FALSE },
|
||||
+ { "[::1]:1234", 8, FALSE },
|
||||
+ { "[2001:db8:3333:4444:5555:6666:7777:8888]", 40,
|
||||
+ FALSE },
|
||||
+ { "[2001:db8::1]", 13, FALSE } };
|
||||
+ BOOL rc = TRUE;
|
||||
+ for (size_t x = 0; x < ARRAYSIZE(tests); x++)
|
||||
+ {
|
||||
+ const struct test_t* cur = &tests[x];
|
||||
+
|
||||
+ const BOOL rc1 = winpr_str_is_valid_url(cur->string);
|
||||
+ const BOOL rc2 = winpr_str_is_valid_urlN(cur->string, cur->len);
|
||||
+
|
||||
+#if defined(WINPR_HAVE_REGCOMP) || defined(WITH_URIPARSER)
|
||||
+ if (rc1 != rc2)
|
||||
+ rc = FALSE;
|
||||
+ if (rc1 != cur->isUrl)
|
||||
+ rc = FALSE;
|
||||
+#else
|
||||
+ fprintf(stderr, "[%s] TODO: !defined(WINPR_HAVE_REGCOMP) && !defined(WITH_URIPARSER)\n",
|
||||
+ __func__);
|
||||
+#endif
|
||||
+ }
|
||||
+
|
||||
+ return rc;
|
||||
+}
|
||||
+
|
||||
+static BOOL test_newline(void)
|
||||
+{
|
||||
+ struct test_t
|
||||
+ {
|
||||
+ char* string;
|
||||
+ size_t len;
|
||||
+ BOOL hasNewlines;
|
||||
+ };
|
||||
+
|
||||
+ const struct test_t tests[] = { { "foo.bar.blabla", 15, FALSE },
|
||||
+ { "somehostname", 12, FALSE },
|
||||
+ { "lala\rgaga\n", 13, TRUE } };
|
||||
+
|
||||
+ for (size_t x = 0; x < ARRAYSIZE(tests); x++)
|
||||
+ {
|
||||
+ const struct test_t* cur = &tests[x];
|
||||
+
|
||||
+ const BOOL rc1 = winpr_str_has_newlines(cur->string);
|
||||
+ if (rc1 != cur->hasNewlines)
|
||||
+ return FALSE;
|
||||
+ }
|
||||
+
|
||||
+ return TRUE;
|
||||
+}
|
||||
+
|
||||
int TestString(int argc, char* argv[])
|
||||
{
|
||||
const WCHAR* p = NULL;
|
||||
@@ -114,6 +188,12 @@ int TestString(int argc, char* argv[])
|
||||
WINPR_UNUSED(argc);
|
||||
WINPR_UNUSED(argv);
|
||||
|
||||
+ if (!test_valid_url())
|
||||
+ return -1;
|
||||
+
|
||||
+ if (!test_newline())
|
||||
+ return -1;
|
||||
+
|
||||
if (!test_winpr_asprintf())
|
||||
return -1;
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user