Bug#964195: guacamole-client: CVE-2020-9497 and CVE-2020-9498

Markus Koschany apo at debian.org
Fri Nov 6 22:07:18 GMT 2020


Control: tags -1 patch


Hi,

I'm attaching my patch for Stretch to this bug report. Since the 
versions in Stretch and unstable are identical, it should work there 
too. However I don't intend to NMU guacamole-server because I believe a 
new upstream version should be packaged instead.

Regards,

Markus
-------------- next part --------------
diff -Nru guacamole-server-0.9.9/debian/patches/CVE-2020-9497-and-CVE-2020-9498.patch guacamole-server-0.9.9/debian/patches/CVE-2020-9497-and-CVE-2020-9498.patch
--- guacamole-server-0.9.9/debian/patches/CVE-2020-9497-and-CVE-2020-9498.patch	1970-01-01 01:00:00.000000000 +0100
+++ guacamole-server-0.9.9/debian/patches/CVE-2020-9497-and-CVE-2020-9498.patch	2020-11-06 22:44:56.000000000 +0100
@@ -0,0 +1,355 @@
+From: Markus Koschany <apo at debian.org>
+Date: Tue, 3 Nov 2020 13:45:20 +0100
+Subject: CVE-2020-9497 and CVE-2020-9498
+
+Bug-Debian: https://bugs.debian.org/964195
+Origin: https://github.com/apache/guacamole-server/commit/a0e11dc81727528224d28466903454e1cb0266bb
+---
+ src/protocols/rdp/guac_rdpdr/rdpdr_fs_messages.c   | 40 ++++++++++++++++++++++
+ .../rdp/guac_rdpdr/rdpdr_fs_messages_file_info.c   | 12 +++++++
+ src/protocols/rdp/guac_rdpdr/rdpdr_messages.c      | 18 ++++++++++
+ src/protocols/rdp/guac_rdpdr/rdpdr_printer.c       |  7 ++++
+ src/protocols/rdp/guac_rdpdr/rdpdr_service.c       |  3 ++
+ src/protocols/rdp/guac_rdpsnd/rdpsnd_messages.c    | 29 ++++++++++++++++
+ src/protocols/rdp/guac_rdpsnd/rdpsnd_service.c     |  5 +++
+ 7 files changed, 114 insertions(+)
+
+diff --git a/src/protocols/rdp/guac_rdpdr/rdpdr_fs_messages.c b/src/protocols/rdp/guac_rdpdr/rdpdr_fs_messages.c
+index bfd8ead..10d41bb 100644
+--- a/src/protocols/rdp/guac_rdpdr/rdpdr_fs_messages.c
++++ b/src/protocols/rdp/guac_rdpdr/rdpdr_fs_messages.c
+@@ -58,6 +58,10 @@ void guac_rdpdr_fs_process_create(guac_rdpdr_device* device,
+     int create_disposition, create_options, path_length;
+     char path[GUAC_RDP_FS_MAX_PATH];
+ 
++    /* Check remaining stream data prior to reading. */
++    if (Stream_GetRemainingLength(input_stream) < 32)
++        return;
++    
+     /* Read "create" information */
+     Stream_Read_UINT32(input_stream, desired_access);
+     Stream_Seek_UINT64(input_stream); /* allocation size */
+@@ -67,6 +71,11 @@ void guac_rdpdr_fs_process_create(guac_rdpdr_device* device,
+     Stream_Read_UINT32(input_stream, create_options);
+     Stream_Read_UINT32(input_stream, path_length);
+ 
++    /* Check to make sure the stream contains path_length bytes. */
++    if(Stream_GetRemainingLength(input_stream) < path_length) {
++        return;
++    }
++
+     /* Convert path to UTF-8 */
+     guac_rdp_utf16_to_utf8(Stream_Pointer(input_stream), path_length/2 - 1,
+             path, sizeof(path));
+@@ -133,6 +142,10 @@ void guac_rdpdr_fs_process_read(guac_rdpdr_device* device,
+ 
+     wStream* output_stream;
+ 
++    /* Check remaining bytes before reading stream. */
++    if (Stream_GetRemainingLength(input_stream) < 12)
++        return;
++    
+     /* Read packet */
+     Stream_Read_UINT32(input_stream, length);
+     Stream_Read_UINT64(input_stream, offset);
+@@ -181,6 +194,10 @@ void guac_rdpdr_fs_process_write(guac_rdpdr_device* device,
+ 
+     wStream* output_stream;
+ 
++    /* Check remaining length. */
++    if (Stream_GetRemainingLength(input_stream) < 32)
++        return;
++    
+     /* Read packet */
+     Stream_Read_UINT32(input_stream, length);
+     Stream_Read_UINT64(input_stream, offset);
+@@ -190,6 +207,11 @@ void guac_rdpdr_fs_process_write(guac_rdpdr_device* device,
+             "%s: [file_id=%i] length=%i, offset=%" PRIu64,
+              __func__, file_id, length, (uint64_t) offset);
+ 
++    /* Check to make sure stream contains at least length bytes */
++    if (Stream_GetRemainingLength(input_stream) < length) {
++        return;
++    }
++
+     /* Attempt write */
+     bytes_written = guac_rdp_fs_write((guac_rdp_fs*) device->data, file_id,
+             offset, Stream_Pointer(input_stream), length);
+@@ -252,6 +274,10 @@ void guac_rdpdr_fs_process_volume_info(guac_rdpdr_device* device, wStream* input
+ 
+     int fs_information_class;
+ 
++    /* Check remaining length */
++    if (Stream_GetRemainingLength(input_stream) < 4)
++        return;
++    
+     Stream_Read_UINT32(input_stream, fs_information_class);
+ 
+     /* Dispatch to appropriate class-specific handler */
+@@ -294,6 +320,10 @@ void guac_rdpdr_fs_process_file_info(guac_rdpdr_device* device, wStream* input_s
+ 
+     int fs_information_class;
+ 
++    /* Check remaining length */
++    if (Stream_GetRemainingLength(input_stream) < 4)
++        return;
++    
+     Stream_Read_UINT32(input_stream, fs_information_class);
+ 
+     /* Dispatch to appropriate class-specific handler */
+@@ -341,6 +371,10 @@ void guac_rdpdr_fs_process_set_file_info(guac_rdpdr_device* device,
+     int fs_information_class;
+     int length;
+ 
++    /* Check remaining length */
++    if (Stream_GetRemainingLength(input_stream) < 32)
++        return;
++    
+     Stream_Read_UINT32(input_stream, fs_information_class);
+     Stream_Read_UINT32(input_stream, length); /* Length */
+     Stream_Seek(input_stream, 24);            /* Padding */
+@@ -423,6 +457,9 @@ void guac_rdpdr_fs_process_query_directory(guac_rdpdr_device* device, wStream* i
+     if (file == NULL)
+         return;
+ 
++    if (Stream_GetRemainingLength(input_stream) < 9)
++        return;
++    
+     /* Read main header */
+     Stream_Read_UINT32(input_stream, fs_information_class);
+     Stream_Read_UINT8(input_stream,  initial_query);
+@@ -431,6 +468,9 @@ void guac_rdpdr_fs_process_query_directory(guac_rdpdr_device* device, wStream* i
+     /* If this is the first query, the path is included after padding */
+     if (initial_query) {
+ 
++        if (Stream_GetRemainingLength(input_stream) < 23 + path_length)
++            return;
++        
+         Stream_Seek(input_stream, 23);       /* Padding */
+ 
+         /* Convert path to UTF-8 */
+diff --git a/src/protocols/rdp/guac_rdpdr/rdpdr_fs_messages_file_info.c b/src/protocols/rdp/guac_rdpdr/rdpdr_fs_messages_file_info.c
+index a0a7a73..99711fe 100644
+--- a/src/protocols/rdp/guac_rdpdr/rdpdr_fs_messages_file_info.c
++++ b/src/protocols/rdp/guac_rdpdr/rdpdr_fs_messages_file_info.c
+@@ -143,11 +143,19 @@ void guac_rdpdr_fs_process_set_rename_info(guac_rdpdr_device* device,
+     wStream* output_stream;
+     char destination_path[GUAC_RDP_FS_MAX_PATH];
+ 
++    /* Check stream size prior to reading. */
++    if (Stream_GetRemainingLength(input_stream) < 6)
++        return;
++    
+     /* Read structure */
+     Stream_Seek_UINT8(input_stream); /* ReplaceIfExists */
+     Stream_Seek_UINT8(input_stream); /* RootDirectory */
+     Stream_Read_UINT32(input_stream, filename_length); /* FileNameLength */
+ 
++    if (Stream_GetRemainingLength(input_stream) < filename_length) {
++        return;
++    }
++
+     /* Convert name to UTF-8 */
+     guac_rdp_utf16_to_utf8(Stream_Pointer(input_stream), filename_length/2,
+             destination_path, sizeof(destination_path));
+@@ -199,6 +207,10 @@ void guac_rdpdr_fs_process_set_allocation_info(guac_rdpdr_device* device,
+     UINT64 size;
+     wStream* output_stream;
+ 
++    if (Stream_GetRemainingLength(input_stream) < 8) {
++        return;
++    }
++
+     /* Read new size */
+     Stream_Read_UINT64(input_stream, size); /* AllocationSize */
+ 
+diff --git a/src/protocols/rdp/guac_rdpdr/rdpdr_messages.c b/src/protocols/rdp/guac_rdpdr/rdpdr_messages.c
+index aa11532..0ef2fbf 100644
+--- a/src/protocols/rdp/guac_rdpdr/rdpdr_messages.c
++++ b/src/protocols/rdp/guac_rdpdr/rdpdr_messages.c
+@@ -150,6 +150,9 @@ void guac_rdpdr_process_server_announce(guac_rdpdrPlugin* rdpdr,
+ 
+     unsigned int major, minor, client_id;
+ 
++    if (Stream_GetRemainingLength(input_stream) < 8)
++        return;
++    
+     Stream_Read_UINT16(input_stream, major);
+     Stream_Read_UINT16(input_stream, minor);
+     Stream_Read_UINT32(input_stream, client_id);
+@@ -177,6 +180,9 @@ void guac_rdpdr_process_device_reply(guac_rdpdrPlugin* rdpdr, wStream* input_str
+     unsigned int device_id, ntstatus;
+     int severity, c, n, facility, code;
+ 
++    if (Stream_GetRemainingLength(input_stream) < 8)
++        return;
++    
+     Stream_Read_UINT32(input_stream, device_id);
+     Stream_Read_UINT32(input_stream, ntstatus);
+ 
+@@ -210,6 +216,9 @@ void guac_rdpdr_process_device_iorequest(guac_rdpdrPlugin* rdpdr, wStream* input
+ 
+     int device_id, file_id, completion_id, major_func, minor_func;
+ 
++    if (Stream_GetRemainingLength(input_stream) < 20)
++        return;
++    
+     /* Read header */
+     Stream_Read_UINT32(input_stream, device_id);
+     Stream_Read_UINT32(input_stream, file_id);
+@@ -237,6 +246,9 @@ void guac_rdpdr_process_server_capability(guac_rdpdrPlugin* rdpdr, wStream* inpu
+     int count;
+     int i;
+ 
++    if (Stream_GetRemainingLength(input_stream) < 4)
++        return;
++    
+     /* Read header */
+     Stream_Read_UINT16(input_stream, count);
+     Stream_Seek(input_stream, 2);
+@@ -247,9 +259,15 @@ void guac_rdpdr_process_server_capability(guac_rdpdrPlugin* rdpdr, wStream* inpu
+         int type;
+         int length;
+ 
++        if (Stream_GetRemainingLength(input_stream) < 4)
++            break;
++        
+         Stream_Read_UINT16(input_stream, type);
+         Stream_Read_UINT16(input_stream, length);
+ 
++        if (Stream_GetRemainingLength(input_stream) < (length - 4))
++            break;
++        
+         /* Ignore all for now */
+         guac_client_log(rdpdr->client, GUAC_LOG_INFO, "Ignoring server capability set type=0x%04x, length=%i", type, length);
+         Stream_Seek(input_stream, length - 4);
+diff --git a/src/protocols/rdp/guac_rdpdr/rdpdr_printer.c b/src/protocols/rdp/guac_rdpdr/rdpdr_printer.c
+index 7aca701..4880304 100644
+--- a/src/protocols/rdp/guac_rdpdr/rdpdr_printer.c
++++ b/src/protocols/rdp/guac_rdpdr/rdpdr_printer.c
+@@ -190,6 +190,9 @@ void guac_rdpdr_process_print_job_write(guac_rdpdr_device* device,
+     int status=0, length;
+     unsigned char* buffer;
+ 
++    if (Stream_GetRemainingLength(input_stream) < 32)
++        return;
++
+     wStream* output_stream;
+ 
+     Stream_Read_UINT32(input_stream, length);
+@@ -197,6 +200,10 @@ void guac_rdpdr_process_print_job_write(guac_rdpdr_device* device,
+     Stream_Seek(input_stream, 20); /* Padding */
+     buffer = Stream_Pointer(input_stream);
+ 
++    if (Stream_GetRemainingLength(input_stream) < length) {
++        return;
++    }
++
+     /* Create print job, if not yet created */
+     if (printer_data->bytes_received == 0) {
+ 
+diff --git a/src/protocols/rdp/guac_rdpdr/rdpdr_service.c b/src/protocols/rdp/guac_rdpdr/rdpdr_service.c
+index 9be53f7..5d507ec 100644
+--- a/src/protocols/rdp/guac_rdpdr/rdpdr_service.c
++++ b/src/protocols/rdp/guac_rdpdr/rdpdr_service.c
+@@ -137,6 +137,9 @@ void guac_rdpdr_process_receive(rdpSvcPlugin* plugin,
+     int component;
+     int packet_id;
+ 
++    if (Stream_GetRemainingLength(input_stream) < 4)
++        return;
++    
+     /* Read header */
+     Stream_Read_UINT16(input_stream, component);
+     Stream_Read_UINT16(input_stream, packet_id);
+diff --git a/src/protocols/rdp/guac_rdpsnd/rdpsnd_messages.c b/src/protocols/rdp/guac_rdpsnd/rdpsnd_messages.c
+index a0827d3..8b58daa 100644
+--- a/src/protocols/rdp/guac_rdpsnd/rdpsnd_messages.c
++++ b/src/protocols/rdp/guac_rdpsnd/rdpsnd_messages.c
+@@ -61,6 +61,10 @@ void guac_rdpsnd_formats_handler(guac_rdpsndPlugin* rdpsnd,
+     /* Get audio stream from client data */
+     guac_audio_stream* audio = client_data->audio;
+ 
++    if (Stream_GetRemainingLength(input_stream) < 20) {
++        return;
++    }
++
+     /* Format header */
+     Stream_Seek(input_stream, 14);
+     Stream_Read_UINT16(input_stream, server_format_count);
+@@ -107,6 +111,11 @@ void guac_rdpsnd_formats_handler(guac_rdpsndPlugin* rdpsnd,
+             /* Remember position in stream */
+             Stream_GetPointer(input_stream, format_start);
+ 
++            /* Check to make sure Stream has at least 18 bytes. */
++            if (Stream_GetRemainingLength(input_stream) < 18) {
++                return;
++            }
++
+             /* Read format */
+             Stream_Read_UINT16(input_stream, format_tag);
+             Stream_Read_UINT16(input_stream, channels);
+@@ -119,6 +128,11 @@ void guac_rdpsnd_formats_handler(guac_rdpsndPlugin* rdpsnd,
+             Stream_Read_UINT16(input_stream, body_size);
+             Stream_Seek(input_stream, body_size);
+ 
++            /* Check that Stream has at least body_size bytes remaining. */
++            if (Stream_GetRemainingLength(input_stream) < body_size) {
++                return;
++            }
++
+             /* If PCM, accept */
+             if (format_tag == WAVE_FORMAT_PCM) {
+ 
+@@ -220,6 +234,11 @@ void guac_rdpsnd_training_handler(guac_rdpsndPlugin* rdpsnd,
+     guac_client* client = rdpsnd->client;
+     rdp_guac_client_data* client_data = (rdp_guac_client_data*) client->data;
+ 
++    /* Check to make sure audio stream contains a minimum number of bytes. */
++    if (Stream_GetRemainingLength(input_stream) < 4) {
++        return;
++    }
++
+     /* Read timestamp and data size */
+     Stream_Read_UINT16(input_stream, rdpsnd->server_timestamp);
+     Stream_Read_UINT16(input_stream, data_size);
+@@ -250,6 +269,11 @@ void guac_rdpsnd_wave_info_handler(guac_rdpsndPlugin* rdpsnd,
+     /* Get audio stream from client data */
+     guac_audio_stream* audio = client_data->audio;
+ 
++    /* Check to make sure audio stream contains a minimum number of bytes. */
++    if (Stream_GetRemainingLength(input_stream) < 12) {
++        return;
++    }
++
+     /* Read wave information */
+     Stream_Read_UINT16(input_stream, rdpsnd->server_timestamp);
+     Stream_Read_UINT16(input_stream, format);
+@@ -288,6 +312,11 @@ void guac_rdpsnd_wave_handler(guac_rdpsndPlugin* rdpsnd,
+     /* Get audio stream from client data */
+     guac_audio_stream* audio = client_data->audio;
+ 
++    /* Verify that the stream has bytes to cover the wave size plus header. */
++    if (Stream_Length(input_stream) < (rdpsnd->incoming_wave_size + 4)) {
++        return;
++    }
++
+     /* Wave Confirmation PDU */
+     wStream* output_stream = Stream_New(NULL, 8);
+ 
+diff --git a/src/protocols/rdp/guac_rdpsnd/rdpsnd_service.c b/src/protocols/rdp/guac_rdpsnd/rdpsnd_service.c
+index 30810ef..88e5c75 100644
+--- a/src/protocols/rdp/guac_rdpsnd/rdpsnd_service.c
++++ b/src/protocols/rdp/guac_rdpsnd/rdpsnd_service.c
+@@ -104,6 +104,11 @@ void guac_rdpsnd_process_receive(rdpSvcPlugin* plugin,
+     guac_rdpsndPlugin* rdpsnd = (guac_rdpsndPlugin*) plugin;
+     guac_rdpsnd_pdu_header header;
+ 
++    /* Check that we have at least the 4 byte header (UINT8 + UINT8 + UINT16) */
++    if (Stream_GetRemainingLength(input_stream) < 4) {
++        return;
++    }
++
+     /* Read RDPSND PDU header */
+     Stream_Read_UINT8(input_stream, header.message_type);
+     Stream_Seek_UINT8(input_stream);
diff -Nru guacamole-server-0.9.9/debian/patches/series guacamole-server-0.9.9/debian/patches/series
--- guacamole-server-0.9.9/debian/patches/series	2016-11-30 16:18:15.000000000 +0100
+++ guacamole-server-0.9.9/debian/patches/series	2020-11-06 22:44:56.000000000 +0100
@@ -1,3 +1,4 @@
 openssl-1.1.patch
 fix-buildsystem.patch
 fix-lfs.patch
+CVE-2020-9497-and-CVE-2020-9498.patch
-------------- next part --------------
A non-text attachment was scrubbed...
Name: OpenPGP_0xD9AD14B9513B51E4.asc
Type: application/pgp-keys
Size: 49647 bytes
Desc: not available
URL: <http://alioth-lists.debian.net/pipermail/pkg-remote-team/attachments/20201106/c90c2fb4/attachment-0001.key>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: OpenPGP_signature
Type: application/pgp-signature
Size: 840 bytes
Desc: OpenPGP digital signature
URL: <http://alioth-lists.debian.net/pipermail/pkg-remote-team/attachments/20201106/c90c2fb4/attachment-0001.sig>


More information about the pkg-remote-team mailing list