Description: fix out-of-bounds write in rdp_recv_tpkt_pdu
Origin: backport, https://github.com/FreeRDP/FreeRDP/commit/03ab68318966c3a22935a02838daaea7b7fbe96c
Bug-Debian: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=869880

Index: freerdp-1.0.2/libfreerdp-core/info.c
===================================================================
--- freerdp-1.0.2.orig/libfreerdp-core/info.c	2013-01-02 16:46:59.000000000 -0500
+++ freerdp-1.0.2/libfreerdp-core/info.c	2017-08-03 07:27:57.291525075 -0400
@@ -586,7 +586,7 @@ boolean rdp_recv_client_info(rdpRdp* rdp
 	if (!rdp_read_header(rdp, s, &length, &channelId))
 		return false;
 
-	rdp_read_security_header(s, &securityFlags);
+	rdp_read_security_header(s, &securityFlags, &length);
 	if ((securityFlags & SEC_INFO_PKT) == 0)
 		return false;
 
@@ -599,7 +599,7 @@ boolean rdp_recv_client_info(rdpRdp* rdp
 		}
 		if (securityFlags & SEC_ENCRYPT)
 		{
-			if (!rdp_decrypt(rdp, s, length - 4, securityFlags))
+			if (!rdp_decrypt(rdp, s, length, securityFlags))
 			{
 				printf("rdp_decrypt failed\n");
 				return false;
Index: freerdp-1.0.2/libfreerdp-core/license.c
===================================================================
--- freerdp-1.0.2.orig/libfreerdp-core/license.c	2013-01-02 16:46:59.000000000 -0500
+++ freerdp-1.0.2/libfreerdp-core/license.c	2017-08-03 07:26:54.491527376 -0400
@@ -180,7 +180,7 @@ boolean license_recv(rdpLicense* license
 		return false;
 	}
 
-	rdp_read_security_header(s, &sec_flags);
+	rdp_read_security_header(s, &sec_flags, &length);
 	if (!(sec_flags & SEC_LICENSE_PKT))
 	{
 		stream_rewind(s, RDP_SECURITY_HEADER_LENGTH);
Index: freerdp-1.0.2/libfreerdp-core/peer.c
===================================================================
--- freerdp-1.0.2.orig/libfreerdp-core/peer.c	2013-01-02 16:46:59.000000000 -0500
+++ freerdp-1.0.2/libfreerdp-core/peer.c	2017-08-03 07:26:10.743528978 -0400
@@ -139,10 +139,10 @@ static boolean peer_recv_tpkt_pdu(freerd
 
 	if (rdp->settings->encryption)
 	{
-		rdp_read_security_header(s, &securityFlags);
+		rdp_read_security_header(s, &securityFlags, &length);
 		if (securityFlags & SEC_ENCRYPT)
 		{
-			if (!rdp_decrypt(rdp, s, length - 4, securityFlags))
+			if (!rdp_decrypt(rdp, s, length, securityFlags))
 			{
 				printf("rdp_decrypt failed\n");
 				return false;
Index: freerdp-1.0.2/libfreerdp-core/rdp.c
===================================================================
--- freerdp-1.0.2.orig/libfreerdp-core/rdp.c	2013-01-02 16:46:59.000000000 -0500
+++ freerdp-1.0.2/libfreerdp-core/rdp.c	2017-08-03 07:36:06.667507148 -0400
@@ -68,11 +68,18 @@ static const char* const DATA_PDU_TYPE_S
  * @param flags security flags
  */
 
-void rdp_read_security_header(STREAM* s, uint16* flags)
+boolean rdp_read_security_header(STREAM* s, uint16* flags, uint16* length)
 {
 	/* Basic Security Header */
+	if (stream_get_left(s) < 4 || (length && (*length < 4)))
+ 		return false;
 	stream_read_uint16(s, *flags); /* flags */
 	stream_seek(s, 2); /* flagsHi (unused) */
+
+	if (length)
+		*length -= 4;
+
+	return true;
 }
 
 /**
@@ -234,6 +241,9 @@ boolean rdp_read_header(rdpRdp* rdp, STR
 	MCSPDU = (rdp->settings->server_mode) ? DomainMCSPDU_SendDataRequest : DomainMCSPDU_SendDataIndication;
 	mcs_read_domain_mcspdu_header(s, &MCSPDU, length);
 
+	if (*length < 8)
+		return false;
+
 	if (*length - 8 > stream_get_left(s))
 		return false;
 
@@ -248,8 +258,10 @@ boolean rdp_read_header(rdpRdp* rdp, STR
 		return true;
 	}
 
-	per_read_integer16(s, &initiator, MCS_BASE_CHANNEL_ID); /* initiator (UserId) */
-	per_read_integer16(s, channel_id, 0); /* channelId */
+	if (!per_read_integer16(s, &initiator, MCS_BASE_CHANNEL_ID)) /* initiator (UserId) */
+		return false;
+	if (!per_read_integer16(s, channel_id, 0)) /* channelId */
+		return false;
 	stream_seek(s, 1); /* dataPriority + Segmentation (0x70) */
 	per_read_length(s, length); /* userData (OCTET_STRING) */
 
@@ -608,6 +620,9 @@ boolean rdp_decrypt(rdpRdp* rdp, STREAM*
 {
 	uint8 cmac[8], wmac[8];
 
+	if (!rdp || !s || length < 0)
+		return false;
+
 	if (rdp->settings->encryption_method == ENCRYPTION_METHOD_FIPS)
 	{
 		uint16 len;
@@ -685,10 +700,10 @@ static boolean rdp_recv_tpkt_pdu(rdpRdp*
 
 	if (rdp->settings->encryption)
 	{
-		rdp_read_security_header(s, &securityFlags);
+		rdp_read_security_header(s, &securityFlags, &length);
 		if (securityFlags & (SEC_ENCRYPT|SEC_REDIRECTION_PKT))
 		{
-			if (!rdp_decrypt(rdp, s, length - 4, securityFlags))
+			if (!rdp_decrypt(rdp, s, length, securityFlags))
 			{
 				printf("rdp_decrypt failed\n");
 				return false;
Index: freerdp-1.0.2/libfreerdp-core/rdp.h
===================================================================
--- freerdp-1.0.2.orig/libfreerdp-core/rdp.h	2013-01-02 16:46:59.000000000 -0500
+++ freerdp-1.0.2/libfreerdp-core/rdp.h	2017-08-03 07:33:00.875513954 -0400
@@ -160,7 +160,7 @@ struct rdp_rdp
 	boolean disconnect;
 };
 
-void rdp_read_security_header(STREAM* s, uint16* flags);
+boolean rdp_read_security_header(STREAM* s, uint16* flags, uint16* length);
 void rdp_write_security_header(STREAM* s, uint16 flags);
 
 boolean rdp_read_share_control_header(STREAM* s, uint16* length, uint16* type, uint16* channel_id);
Index: freerdp-1.0.2/libfreerdp-core/capabilities.c
===================================================================
--- freerdp-1.0.2.orig/libfreerdp-core/capabilities.c	2013-01-02 16:46:59.000000000 -0500
+++ freerdp-1.0.2/libfreerdp-core/capabilities.c	2017-08-03 08:01:30.955451311 -0400
@@ -1803,10 +1803,10 @@ boolean rdp_recv_demand_active(rdpRdp* r
 
 	if (rdp->settings->encryption)
 	{
-		rdp_read_security_header(s, &securityFlags);
+		rdp_read_security_header(s, &securityFlags, &length);
 		if (securityFlags & SEC_ENCRYPT)
 		{
-			if (!rdp_decrypt(rdp, s, length - 4, securityFlags))
+			if (!rdp_decrypt(rdp, s, length, securityFlags))
 			{
 				printf("rdp_decrypt failed\n");
 				return false;
@@ -1937,10 +1937,10 @@ boolean rdp_recv_confirm_active(rdpRdp*
 
 	if (rdp->settings->encryption)
 	{
-		rdp_read_security_header(s, &securityFlags);
+		rdp_read_security_header(s, &securityFlags, &length);
 		if (securityFlags & SEC_ENCRYPT)
 		{
-			if (!rdp_decrypt(rdp, s, length - 4, securityFlags))
+			if (!rdp_decrypt(rdp, s, length, securityFlags))
 			{
 				printf("rdp_decrypt failed\n");
 				return false;
Index: freerdp-1.0.2/libfreerdp-core/connection.c
===================================================================
--- freerdp-1.0.2.orig/libfreerdp-core/connection.c	2013-01-02 16:46:59.000000000 -0500
+++ freerdp-1.0.2/libfreerdp-core/connection.c	2017-08-03 08:08:12.211436612 -0400
@@ -266,7 +266,7 @@ static boolean rdp_server_establish_keys
 		printf("rdp_server_establish_keys: invalid RDP header\n");
 		return false;
 	}
-	rdp_read_security_header(s, &sec_flags);
+	rdp_read_security_header(s, &sec_flags, &length);
 	if ((sec_flags & SEC_EXCHANGE_PKT) == 0)
 	{
 		printf("rdp_server_establish_keys: missing SEC_EXCHANGE_PKT in security header\n");
