From 708d0cb3c0a8195acb19718d0214b7360044cc8a Mon Sep 17 00:00:00 2001 From: David FORT Date: Tue, 26 Jan 2016 16:14:48 +0100 Subject: [PATCH] Check server and client capabilities Most of the capabilities are sent by both the client and the server. But for some the specs specify that they are only supposed to be only send by the server or the client. This patch ensures this. Without this patch a malicious client can change server settings and a malicious server can modify client settings. --- libfreerdp/core/capabilities.c | 160 ++++++++++++++++++++++++----------------- 1 file changed, 95 insertions(+), 65 deletions(-) diff --git a/libfreerdp/core/capabilities.c b/libfreerdp/core/capabilities.c index 46bc998..8205f43 100644 --- a/libfreerdp/core/capabilities.c +++ b/libfreerdp/core/capabilities.c @@ -31,8 +31,6 @@ #define TAG FREERDP_TAG("core.capabilities") -#ifdef WITH_DEBUG_CAPABILITIES - const char* const CAPSET_TYPE_STRINGS[] = { "Unknown", @@ -68,7 +66,13 @@ const char* const CAPSET_TYPE_STRINGS[] = "Frame Acknowledge" }; -#endif +static const char *get_capability_name(UINT16 type) +{ + if (type > CAPSET_TYPE_FRAME_ACKNOWLEDGE) + return ""; + + return CAPSET_TYPE_STRINGS[type]; +} BOOL rdp_print_capability_sets(wStream* s, UINT16 numberCapabilities, BOOL receiving); @@ -3401,6 +3405,7 @@ BOOL rdp_read_capability_sets(wStream* s, rdpSettings* settings, UINT16 numberCa UINT16 type; UINT16 length; BYTE *bm, *em; + BOOL treated; Stream_GetPointer(s, mark); count = numberCapabilities; @@ -3428,6 +3433,7 @@ BOOL rdp_read_capability_sets(wStream* s, rdpSettings* settings, UINT16 numberCa return FALSE; } + treated = TRUE; switch (type) { case CAPSET_TYPE_GENERAL: @@ -3445,23 +3451,18 @@ BOOL rdp_read_capability_sets(wStream* s, rdpSettings* settings, UINT16 numberCa return FALSE; break; - case CAPSET_TYPE_BITMAP_CACHE: - if (!rdp_read_bitmap_cache_capability_set(s, length, settings)) - return FALSE; - break; - - case CAPSET_TYPE_CONTROL: - if (!rdp_read_control_capability_set(s, length, settings)) + case CAPSET_TYPE_POINTER: + if (!rdp_read_pointer_capability_set(s, length, settings)) return FALSE; break; - case CAPSET_TYPE_ACTIVATION: - if (!rdp_read_window_activation_capability_set(s, length, settings)) + case CAPSET_TYPE_INPUT: + if (!rdp_read_input_capability_set(s, length, settings)) return FALSE; break; - case CAPSET_TYPE_POINTER: - if (!rdp_read_pointer_capability_set(s, length, settings)) + case CAPSET_TYPE_VIRTUAL_CHANNEL: + if (!rdp_read_virtual_channel_capability_set(s, length, settings)) return FALSE; break; @@ -3475,56 +3476,11 @@ BOOL rdp_read_capability_sets(wStream* s, rdpSettings* settings, UINT16 numberCa return FALSE; break; - case CAPSET_TYPE_SOUND: - if (!rdp_read_sound_capability_set(s, length, settings)) - return FALSE; - break; - - case CAPSET_TYPE_INPUT: - if (!rdp_read_input_capability_set(s, length, settings)) - return FALSE; - break; - case CAPSET_TYPE_FONT: if (!rdp_read_font_capability_set(s, length, settings)) return FALSE; break; - case CAPSET_TYPE_BRUSH: - if (!rdp_read_brush_capability_set(s, length, settings)) - return FALSE; - break; - - case CAPSET_TYPE_GLYPH_CACHE: - if (!rdp_read_glyph_cache_capability_set(s, length, settings)) - return FALSE; - break; - - case CAPSET_TYPE_OFFSCREEN_CACHE: - if (!rdp_read_offscreen_bitmap_cache_capability_set(s, length, settings)) - return FALSE; - break; - - case CAPSET_TYPE_BITMAP_CACHE_HOST_SUPPORT: - if (!rdp_read_bitmap_cache_host_support_capability_set(s, length, settings)) - return FALSE; - break; - - case CAPSET_TYPE_BITMAP_CACHE_V2: - if (!rdp_read_bitmap_cache_v2_capability_set(s, length, settings)) - return FALSE; - break; - - case CAPSET_TYPE_VIRTUAL_CHANNEL: - if (!rdp_read_virtual_channel_capability_set(s, length, settings)) - return FALSE; - break; - - case CAPSET_TYPE_DRAW_NINE_GRID_CACHE: - if (!rdp_read_draw_nine_grid_cache_capability_set(s, length, settings)) - return FALSE; - break; - case CAPSET_TYPE_DRAW_GDI_PLUS: if (!rdp_read_draw_gdiplus_cache_capability_set(s, length, settings)) return FALSE; @@ -3540,11 +3496,6 @@ BOOL rdp_read_capability_sets(wStream* s, rdpSettings* settings, UINT16 numberCa return FALSE; break; - case CAPSET_TYPE_COMP_DESK: - if (!rdp_read_desktop_composition_capability_set(s, length, settings)) - return FALSE; - break; - case CAPSET_TYPE_MULTI_FRAGMENT_UPDATE: if (!rdp_read_multifragment_update_capability_set(s, length, settings)) return FALSE; @@ -3555,6 +3506,11 @@ BOOL rdp_read_capability_sets(wStream* s, rdpSettings* settings, UINT16 numberCa return FALSE; break; + case CAPSET_TYPE_COMP_DESK: + if (!rdp_read_desktop_composition_capability_set(s, length, settings)) + return FALSE; + break; + case CAPSET_TYPE_SURFACE_COMMANDS: if (!rdp_read_surface_commands_capability_set(s, length, settings)) return FALSE; @@ -3576,10 +3532,84 @@ BOOL rdp_read_capability_sets(wStream* s, rdpSettings* settings, UINT16 numberCa break; default: - WLog_ERR(TAG, "unknown capability type %d", type); + treated = FALSE; break; } + if (!treated) + { + if (settings->ServerMode) + { + /* treating capabilities that are supposed to be send only from the client */ + switch (type) + { + case CAPSET_TYPE_BITMAP_CACHE: + if (!rdp_read_bitmap_cache_capability_set(s, length, settings)) + return FALSE; + break; + + case CAPSET_TYPE_BITMAP_CACHE_V2: + if (!rdp_read_bitmap_cache_v2_capability_set(s, length, settings)) + return FALSE; + break; + + case CAPSET_TYPE_BRUSH: + if (!rdp_read_brush_capability_set(s, length, settings)) + return FALSE; + break; + + case CAPSET_TYPE_GLYPH_CACHE: + if (!rdp_read_glyph_cache_capability_set(s, length, settings)) + return FALSE; + break; + + case CAPSET_TYPE_OFFSCREEN_CACHE: + if (!rdp_read_offscreen_bitmap_cache_capability_set(s, length, settings)) + return FALSE; + break; + + case CAPSET_TYPE_SOUND: + if (!rdp_read_sound_capability_set(s, length, settings)) + return FALSE; + break; + + case CAPSET_TYPE_CONTROL: + if (!rdp_read_control_capability_set(s, length, settings)) + return FALSE; + break; + + case CAPSET_TYPE_ACTIVATION: + if (!rdp_read_window_activation_capability_set(s, length, settings)) + return FALSE; + break; + + case CAPSET_TYPE_DRAW_NINE_GRID_CACHE: + if (!rdp_read_draw_nine_grid_cache_capability_set(s, length, settings)) + return FALSE; + break; + + default: + WLog_ERR(TAG, "capability %s(%d) not expected from client", get_capability_name(type), type); + return FALSE; + } + } + else + { + /* treating capabilities that are supposed to be send only from the server */ + switch (type) + { + case CAPSET_TYPE_BITMAP_CACHE_HOST_SUPPORT: + if (!rdp_read_bitmap_cache_host_support_capability_set(s, length, settings)) + return FALSE; + break; + + default: + WLog_ERR(TAG, "capability %s(%d) not expected from server", get_capability_name(type), type); + return FALSE; + } + } + } + if (s->pointer != em) { WLog_ERR(TAG, "incorrect offset, type:0x%02X actual:%d expected:%d", -- 2.7.4