Backport several CVE fixes
It fixes CVE-2026-67289, CVE-2026-67299 and CVE-2026-68580. Resolves: RHEL-222792, RHEL-222965, RHEL-223607 Co-authored-by: Ondrej Holy <oholy@redhat.com>
This commit is contained in:
parent
d8e8413c9c
commit
c2efdf022e
37
channels-audin-limit-FramesPerPacket.patch
Normal file
37
channels-audin-limit-FramesPerPacket.patch
Normal file
@ -0,0 +1,37 @@
|
||||
From 22cc4e8e563eaed5628bf510f26091d554d8533d 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 4c5e7977d..697fd2848 100644
|
||||
--- a/channels/audin/client/audin_main.c
|
||||
+++ b/channels/audin/client/audin_main.c
|
||||
@@ -487,7 +487,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)
|
||||
{
|
||||
@@ -496,6 +495,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))
|
||||
222
channels-audin-tighten-parameter-checks.patch
Normal file
222
channels-audin-tighten-parameter-checks.patch
Normal file
@ -0,0 +1,222 @@
|
||||
From cc57fb28a27f8563375ac435a9f16985135a1789 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 | 40 ++++++++++++++--------
|
||||
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, 48 insertions(+), 30 deletions(-)
|
||||
|
||||
diff --git a/channels/audin/client/alsa/audin_alsa.c b/channels/audin/client/alsa/audin_alsa.c
|
||||
index 20564dc04..3882b734f 100644
|
||||
--- a/channels/audin/client/alsa/audin_alsa.c
|
||||
+++ b/channels/audin/client/alsa/audin_alsa.c
|
||||
@@ -139,8 +139,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 a447dac34..c4598a634 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;
|
||||
@@ -108,8 +108,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)
|
||||
@@ -202,7 +202,7 @@ static SLresult openSLRecOpen(OPENSL_STREAM* p)
|
||||
}
|
||||
else
|
||||
{
|
||||
- WLog_ERR(TAG, "bits_per_sample=%" PRIu32, p->bits_per_sample);
|
||||
+ WLog_ERR(TAG, "bits_per_sample=%" PRIuz, p->bits_per_sample);
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -314,24 +314,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 nullptr;
|
||||
|
||||
- p = (OPENSL_STREAM*)calloc(1, sizeof(OPENSL_STREAM));
|
||||
+ OPENSL_STREAM* p = (OPENSL_STREAM*)calloc(1, sizeof(OPENSL_STREAM));
|
||||
|
||||
if (!p)
|
||||
return nullptr;
|
||||
|
||||
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))
|
||||
@@ -343,9 +350,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 4f9b2db4f..bdba57cab 100644
|
||||
--- a/channels/audin/client/opensles/opensl_io.h
|
||||
+++ b/channels/audin/client/opensles/opensl_io.h
|
||||
@@ -56,10 +56,9 @@ extern "C"
|
||||
size in frames. Returns a handle to the OpenSL stream
|
||||
*/
|
||||
WINPR_ATTR_MALLOC(android_CloseRecDevice, 1)
|
||||
- WINPR_ATTR_NODISCARD
|
||||
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);
|
||||
#ifdef __cplusplus
|
||||
};
|
||||
#endif
|
||||
diff --git a/channels/audin/client/oss/audin_oss.c b/channels/audin/client/oss/audin_oss.c
|
||||
index f709130be..d2e10ef3d 100644
|
||||
--- a/channels/audin/client/oss/audin_oss.c
|
||||
+++ b/channels/audin/client/oss/audin_oss.c
|
||||
@@ -190,6 +190,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 (nullptr == buffer)
|
||||
diff --git a/channels/audin/client/sndio/audin_sndio.c b/channels/audin/client/sndio/audin_sndio.c
|
||||
index d922855be..6da44e612 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 = nullptr;
|
||||
- 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 == nullptr)
|
||||
diff --git a/channels/audin/client/winmm/audin_winmm.c b/channels/audin/client/winmm/audin_winmm.c
|
||||
index 0c1cd3867..573d1d6d1 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 = nullptr;
|
||||
- int size = 0;
|
||||
WAVEHDR waveHdr[4] = WINPR_C_ARRAY_INIT;
|
||||
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]));
|
||||
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 bc37414b55a6061995fed3ee61836aaecfb055f6 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 1d61fd333..e9dda6ac2 100644
|
||||
--- a/libfreerdp/core/message.c
|
||||
+++ b/libfreerdp/core/message.c
|
||||
@@ -1297,30 +1297,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 = nullptr;
|
||||
- WINDOW_ICON_ORDER* lParam = nullptr;
|
||||
- rdp_update_internal* up = nullptr;
|
||||
-
|
||||
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)
|
||||
@@ -1356,7 +1355,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:
|
||||
178
core-redirection-check-redirection-values-for-validity.patch
Normal file
178
core-redirection-check-redirection-values-for-validity.patch
Normal file
@ -0,0 +1,178 @@
|
||||
From c720ad9f8e9a308c035d029b1d61b249a525f474 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 | 10 ++++++++++
|
||||
libfreerdp/core/redirection.c | 25 ++++++++++++++++++++-----
|
||||
libfreerdp/core/utils.c | 19 +++++++++++++++++++
|
||||
libfreerdp/core/utils.h | 2 ++
|
||||
4 files changed, 51 insertions(+), 5 deletions(-)
|
||||
|
||||
diff --git a/libfreerdp/core/gateway/arm.c b/libfreerdp/core/gateway/arm.c
|
||||
index 804d0c4f9..4bb62882e 100644
|
||||
--- a/libfreerdp/core/gateway/arm.c
|
||||
+++ b/libfreerdp/core/gateway/arm.c
|
||||
@@ -685,6 +685,9 @@ static BOOL arm_parse_ipv6(rdpSettings* settings, WINPR_JSON* ipv6, size_t* pAdd
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
+ if (!winpr_str_is_valid_url(addr))
|
||||
+ return FALSE;
|
||||
+
|
||||
if (!freerdp_settings_set_pointer_array(settings, FreeRDP_TargetNetAddresses,
|
||||
(*pAddressIdx)++, addr))
|
||||
return FALSE;
|
||||
@@ -722,6 +725,10 @@ static BOOL arm_parse_ipv4(rdpSettings* settings, WINPR_JSON* ipv4, size_t* pAdd
|
||||
WLog_ERR(TAG, "Exceeded TargetNetAddresses, parsing failed");
|
||||
return FALSE;
|
||||
}
|
||||
+
|
||||
+ if (!utils_is_valid_ip(publicIp))
|
||||
+ return FALSE;
|
||||
+
|
||||
if (!freerdp_settings_set_pointer_array(settings, FreeRDP_TargetNetAddresses,
|
||||
(*pAddressIdx)++, publicIp))
|
||||
return FALSE;
|
||||
@@ -740,6 +747,9 @@ static BOOL arm_parse_ipv4(rdpSettings* settings, WINPR_JSON* ipv4, size_t* pAdd
|
||||
WLog_ERR(TAG, "Exceeded TargetNetAddresses, parsing failed");
|
||||
return FALSE;
|
||||
}
|
||||
+ 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 57971a4f7..c30bce904 100644
|
||||
--- a/libfreerdp/core/redirection.c
|
||||
+++ b/libfreerdp/core/redirection.c
|
||||
@@ -707,6 +707,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)
|
||||
@@ -720,13 +722,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);
|
||||
}
|
||||
|
||||
@@ -734,7 +740,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);
|
||||
}
|
||||
|
||||
@@ -792,7 +799,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);
|
||||
}
|
||||
|
||||
@@ -800,7 +808,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);
|
||||
}
|
||||
|
||||
@@ -809,6 +818,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)
|
||||
@@ -870,7 +881,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]);
|
||||
}
|
||||
@@ -898,7 +910,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 c2e79608c..226e7527f 100644
|
||||
--- a/libfreerdp/core/utils.c
|
||||
+++ b/libfreerdp/core/utils.c
|
||||
@@ -597,3 +597,22 @@ const char* guid2str(const GUID* guid, char* buffer, size_t len)
|
||||
RpcStringFreeA(&strguid);
|
||||
return buffer;
|
||||
}
|
||||
+
|
||||
+static BOOL isValidIPv4(const char* ipAddress)
|
||||
+{
|
||||
+ struct sockaddr_in sa = WINPR_C_ARRAY_INIT;
|
||||
+ int result = inet_pton(AF_INET, ipAddress, &(sa.sin_addr));
|
||||
+ return result != 0;
|
||||
+}
|
||||
+
|
||||
+static BOOL isValidIPv6(const char* ipAddress)
|
||||
+{
|
||||
+ struct sockaddr_in6 sa = WINPR_C_ARRAY_INIT;
|
||||
+ 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 d683db1da..d5725ea72 100644
|
||||
--- a/libfreerdp/core/utils.h
|
||||
+++ b/libfreerdp/core/utils.h
|
||||
@@ -115,4 +115,6 @@ BOOL freerdp_areApplicationDetailsCustomized(void);
|
||||
|
||||
FREERDP_LOCAL const char* guid2str(const GUID* guid, char* buffer, size_t len);
|
||||
|
||||
+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 cef38c3063c8f5d6d62bdfff3234b6499cb4c589 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 c30bce904..9aaab65ec 100644
|
||||
--- a/libfreerdp/core/redirection.c
|
||||
+++ b/libfreerdp/core/redirection.c
|
||||
@@ -722,9 +722,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)
|
||||
@@ -818,8 +815,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)
|
||||
23
freerdp.spec
23
freerdp.spec
@ -30,7 +30,7 @@
|
||||
Name: freerdp
|
||||
Epoch: 2
|
||||
Version: 3.28.0
|
||||
Release: 1%{?dist}
|
||||
Release: 2%{?dist}
|
||||
Summary: Free implementation of the Remote Desktop Protocol (RDP)
|
||||
|
||||
# The effective license is Apache-2.0 but:
|
||||
@ -47,6 +47,23 @@ URL: http://www.freerdp.com/
|
||||
Source0: FreeRDP-%{version}-repack.tar.gz
|
||||
Source1: freerdp_download_and_repack.sh
|
||||
|
||||
# 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++
|
||||
@ -379,6 +396,10 @@ find %{buildroot} -name "*.a" -delete
|
||||
%{_libdir}/pkgconfig/winpr-tools3.pc
|
||||
|
||||
%changelog
|
||||
* Mon Aug 17 2026 RHEL Packaging Agent <redhat-ymir-agent@redhat.com> - 2:3.28.0-2
|
||||
- Backport several CVE fixes (CVE-2026-67289, CVE-2026-67299, CVE-2026-68580)
|
||||
Resolves: RHEL-222792, RHEL-222965, RHEL-223607
|
||||
|
||||
* Mon Jul 13 2026 Ondrej Holy <oholy@redhat.com> - 2:3.28.0-1
|
||||
- Update to 3.28.0 (CVE-2026-57156, CVE-2026-57157, CVE-2026-57158)
|
||||
Resolves: RHEL-171999
|
||||
|
||||
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 03074b64415bf757be38549e44fa98a8d92a56ed 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 | 28 +++++++
|
||||
winpr/libwinpr/crt/CMakeLists.txt | 8 ++
|
||||
winpr/libwinpr/crt/string.c | 115 +++++++++++++++++++++++++++
|
||||
winpr/libwinpr/crt/test/TestString.c | 79 ++++++++++++++++++
|
||||
4 files changed, 230 insertions(+)
|
||||
|
||||
diff --git a/winpr/include/winpr/string.h b/winpr/include/winpr/string.h
|
||||
index 8163618ec..7fb3af570 100644
|
||||
--- a/winpr/include/winpr/string.h
|
||||
+++ b/winpr/include/winpr/string.h
|
||||
@@ -53,6 +53,34 @@ extern "C"
|
||||
WINPR_API WINPR_ATTR_MALLOC(free, 1) char* winpr_str_url_encode(const char* str, size_t len);
|
||||
WINPR_API WINPR_ATTR_MALLOC(free, 1) 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_ATTR_NODISCARD
|
||||
+ 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_ATTR_NODISCARD
|
||||
+ 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_ATTR_NODISCARD
|
||||
+ 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 8e07d0e87..1ea112e3f 100644
|
||||
--- a/winpr/libwinpr/crt/CMakeLists.txt
|
||||
+++ b/winpr/libwinpr/crt/CMakeLists.txt
|
||||
@@ -25,6 +25,14 @@ set(CRT_FILES
|
||||
assert.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 872fd1cd4..0fb1c029e 100644
|
||||
--- a/winpr/libwinpr/crt/string.c
|
||||
+++ b/winpr/libwinpr/crt/string.c
|
||||
@@ -34,12 +34,38 @@
|
||||
#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"
|
||||
#define TAG WINPR_TAG("crt")
|
||||
|
||||
#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 = nullptr;
|
||||
+ UriUriA uri = WINPR_C_ARRAY_INIT;
|
||||
+ 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 = nullptr;
|
||||
+ UriUriA uri = WINPR_C_ARRAY_INIT;
|
||||
+ 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);
|
||||
@@ -152,6 +178,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 = WINPR_C_ARRAY_INIT;
|
||||
+ 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, nullptr, 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)
|
||||
@@ -866,3 +945,39 @@ char* winpr_strnstr(char* haystack, const char* needle, size_t hlen)
|
||||
return nullptr;
|
||||
#endif
|
||||
}
|
||||
+
|
||||
+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 3d0804e8c..31c82f22f 100644
|
||||
--- a/winpr/libwinpr/crt/test/TestString.c
|
||||
+++ b/winpr/libwinpr/crt/test/TestString.c
|
||||
@@ -163,6 +163,79 @@ static BOOL test_winpr_strnstr(void)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
+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 = nullptr;
|
||||
@@ -173,6 +246,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