Cumulative security patch from commit 58606fd98722e92aaa4c2c7b8cb99cc92bd4308c

58606fd EAP-pwd server: Make sure in_frag_pos is cleared to zero on allocation
6aa5d95 EAP-pwd peer: Make sure in_frag_pos is cleared to zero on allocation
28a069a EAP-pwd peer: Fix asymmetric fragmentation behavior
3035cc2 EAP-pwd server: Fix Total-Length parsing for fragment reassembly
477c743 EAP-pwd peer: Fix Total-Length parsing for fragment reassembly
e28a58b EAP-pwd server: Fix payload length validation for Commit and Confirm
dd2f043 EAP-pwd peer: Fix payload length validation for Commit and Confirm
ef566a4 AP WMM: Fix integer underflow in WMM Action frame parser
8640cf7 WPS: Add more debug prints to httpread
1bd0d57 WPS: Replace the httpread_debug design with standard debug prints
7da4f4b WPS: Check maximum HTTP body length earlier in the process
af185d0 WPS: Extra validation step for HTTP reader
5acd23f WPS: Fix HTTP chunked transfer encoding parser
a5da657 dbus: Stop ongoing scheduled scan when scan is requested
0c28071 Fix sending ANQP request to an unknown BSS while associated
74197e0 wpa_cli: Fix memory leak when tracking networks
4504621 TDLS: Add TDLS_LINK_STATUS command to the control interface
01e87ef IBSS: Check ibss_rsn init before starting new IBSS authentication
74d912f libtommath: Fix check mp_init_multi() result
fd66aa6 Check Public Action length explicitly before reading Action Code
ff4a6d4 EAP-SIM/AKA: Explicitly check for header to include Reserved field
f5ed400 EAP-SAKE: Make attribute parser more readable
0dfb7be EAP-SAKE: Pass EAP identifier instead of full request
354e3f7 TLS: Fix debug dump of X.509 certificate
87fcb5a EAP-PAX: Fix PAX_STD-1 and PAX_STD-3 payload length validation
c3c5615 EAP-GPSK: Pass EAP identifier instead of full request
d36c803 EAP-TLS/PEAP/TTLS/FAST: Move more towards using struct wpabuf
8d9f3b8 EAP-FAST: Do not use type cast to remove const specification
07f9034 EAP-FAST: Pass EAP identifier instead of full request
f153e41 EAP-EKE: Do not pass full request to eap_eke_build_fail()
53f376c Fix a typo in function documentation
5aeebc4 D-Bus Fix network_is_persistent_group() for P2P operations
5441da2 Fix wpas_notify_network_removed()
e8181e2 dbus: Add a debug print on fill_dict_with_properties() getter failures
8a78e22 D-Bus: Fix operations when P2P management interface is used
dea0d8e RADIUS: Fix a copy-paste error in variable name

Change-Id: Ib70bf513c1f6c17974ef135806e44e120a5d5709
Signed-off-by: Dmitry Shmidt <dimitrysh@google.com>
diff --git a/src/wps/httpread.c b/src/wps/httpread.c
index 2f08f37..180b572 100644
--- a/src/wps/httpread.c
+++ b/src/wps/httpread.c
@@ -44,16 +44,6 @@
 #define HTTPREAD_HEADER_MAX_SIZE 4096   /* max allowed for headers */
 #define HTTPREAD_BODYBUF_DELTA 4096     /* increase allocation by this */
 
-#if 0
-/* httpread_debug -- set this global variable > 0 e.g. from debugger
- * to enable debugs (larger numbers for more debugs)
- * Make this a #define of 0 to eliminate the debugging code.
- */
-int httpread_debug = 99;
-#else
-#define httpread_debug 0        /* eliminates even the debugging code */
-#endif
-
 
 /* control instance -- actual definition (opaque to application)
  */
@@ -136,8 +126,7 @@
  */
 void httpread_destroy(struct httpread *h)
 {
-	if (httpread_debug >= 10)
-		wpa_printf(MSG_DEBUG, "ENTER httpread_destroy(%p)", h);
+	wpa_printf(MSG_DEBUG, "httpread_destroy(%p)", h);
 	if (!h)
 		return;
 
@@ -177,6 +166,12 @@
 		if (!isdigit(*hbp))
 			return -1;
 		h->content_length = atol(hbp);
+		if (h->content_length < 0 || h->content_length > h->max_bytes) {
+			wpa_printf(MSG_DEBUG,
+				   "httpread: Unacceptable Content-Length %d",
+				   h->content_length);
+			return -1;
+		}
 		h->got_content_length = 1;
 		return 0;
 	}
@@ -380,15 +375,16 @@
 	char *bbp;      /* pointer into body buffer */
 	char readbuf[HTTPREAD_READBUF_SIZE];  /* temp use to read into */
 
-	if (httpread_debug >= 20)
-		wpa_printf(MSG_DEBUG, "ENTER httpread_read_handler(%p)", h);
-
 	/* read some at a time, then search for the interal
 	 * boundaries between header and data and etc.
 	 */
+	wpa_printf(MSG_DEBUG, "httpread: Trying to read more data(%p)", h);
 	nread = read(h->sd, readbuf, sizeof(readbuf));
-	if (nread < 0)
+	if (nread < 0) {
+		wpa_printf(MSG_DEBUG, "httpread failed: %s", strerror(errno));
 		goto bad;
+	}
+	wpa_hexdump_ascii(MSG_MSGDUMP, "httpread - read", readbuf, nread);
 	if (nread == 0) {
 		/* end of transmission... this may be normal
 		 * or may be an error... in some cases we can't
@@ -411,8 +407,7 @@
 		 * although dropped connections can cause false
 		 * end
 		 */
-		if (httpread_debug >= 10)
-			wpa_printf(MSG_DEBUG, "httpread ok eof(%p)", h);
+		wpa_printf(MSG_DEBUG, "httpread ok eof(%p)", h);
 		h->got_body = 1;
 		goto got_file;
 	}
@@ -432,6 +427,8 @@
 			if (nread == 0)
 				goto get_more;
 			if (h->hdr_nbytes == HTTPREAD_HEADER_MAX_SIZE) {
+				wpa_printf(MSG_DEBUG,
+					   "httpread: Too long header");
 				goto bad;
 			}
 			*hbp++ = *rbp++;
@@ -453,16 +450,13 @@
 			goto bad;
 		}
 		if (h->max_bytes == 0) {
-			if (httpread_debug >= 10)
-				wpa_printf(MSG_DEBUG,
-					   "httpread no body hdr end(%p)", h);
+			wpa_printf(MSG_DEBUG, "httpread no body hdr end(%p)",
+				   h);
 			goto got_file;
 		}
 		if (h->got_content_length && h->content_length == 0) {
-			if (httpread_debug >= 10)
-				wpa_printf(MSG_DEBUG,
-					   "httpread zero content length(%p)",
-					   h);
+			wpa_printf(MSG_DEBUG,
+				   "httpread zero content length(%p)", h);
 			goto got_file;
 		}
 	}
@@ -475,9 +469,7 @@
 	    !os_strncasecmp(h->hdr, "HEAD", 4) ||
 	    !os_strncasecmp(h->hdr, "GET", 3)) {
 		if (!h->got_body) {
-			if (httpread_debug >= 10)
-				wpa_printf(MSG_DEBUG,
-					   "httpread NO BODY for sp. type");
+			wpa_printf(MSG_DEBUG, "httpread NO BODY for sp. type");
 		}
 		h->got_body = 1;
 		goto got_file;
@@ -498,8 +490,12 @@
 			char *new_body;
 			int new_alloc_nbytes;
 
-			if (h->body_nbytes >= h->max_bytes)
+			if (h->body_nbytes >= h->max_bytes) {
+				wpa_printf(MSG_DEBUG,
+					   "httpread: body_nbytes=%d >= max_bytes=%d",
+					   h->body_nbytes, h->max_bytes);
 				goto bad;
+			}
 			new_alloc_nbytes = h->body_alloc_nbytes +
 				HTTPREAD_BODYBUF_DELTA;
 			/* For content-length case, the first time
@@ -509,9 +505,20 @@
 			if (h->got_content_length &&
 			    new_alloc_nbytes < (h->content_length + 1))
 				new_alloc_nbytes = h->content_length + 1;
-			if ((new_body = os_realloc(h->body, new_alloc_nbytes))
-			    == NULL)
+			if (new_alloc_nbytes < h->body_alloc_nbytes ||
+			    new_alloc_nbytes > h->max_bytes) {
+				wpa_printf(MSG_DEBUG,
+					   "httpread: Unacceptable body length %d",
+					   new_alloc_nbytes);
 				goto bad;
+			}
+			if ((new_body = os_realloc(h->body, new_alloc_nbytes))
+			    == NULL) {
+				wpa_printf(MSG_DEBUG,
+					   "httpread: Failed to reallocate buffer (len=%d)",
+					   new_alloc_nbytes);
+				goto bad;
+			}
 
 			h->body = new_body;
 			h->body_alloc_nbytes = new_alloc_nbytes;
@@ -530,9 +537,19 @@
 					/* hdr line consists solely
 					 * of a hex numeral and CFLF
 					 */
-					if (!isxdigit(*cbp))
+					if (!isxdigit(*cbp)) {
+						wpa_printf(MSG_DEBUG,
+							   "httpread: Unexpected chunk header value (not a hex digit)");
 						goto bad;
+					}
 					h->chunk_size = strtoul(cbp, NULL, 16);
+					if (h->chunk_size < 0 ||
+					    h->chunk_size > h->max_bytes) {
+						wpa_printf(MSG_DEBUG,
+							   "httpread: Invalid chunk size %d",
+							   h->chunk_size);
+						goto bad;
+					}
 					/* throw away chunk header
 					 * so we have only real data
 					 */
@@ -542,10 +559,9 @@
 						/* end of chunking */
 						/* trailer follows */
 						h->in_trailer = 1;
-						if (httpread_debug >= 20)
-							wpa_printf(
-								MSG_DEBUG,
-								"httpread end chunks(%p)", h);
+						wpa_printf(MSG_DEBUG,
+							   "httpread end chunks(%p)",
+							   h);
 						break;
 					}
 					h->in_chunk_data = 1;
@@ -563,8 +579,11 @@
 					 */
 					if (bbp[-1] == '\n' &&
 					    bbp[-2] == '\r') {
-					} else
+					} else {
+						wpa_printf(MSG_DEBUG,
+							   "httpread: Invalid chunk end");
 						goto bad;
+					}
 					h->body_nbytes -= 2;
 					bbp -= 2;
 					h->chunk_start = h->body_nbytes;
@@ -574,10 +593,8 @@
 			} else if (h->got_content_length &&
 				   h->body_nbytes >= h->content_length) {
 				h->got_body = 1;
-				if (httpread_debug >= 10)
-					wpa_printf(
-						MSG_DEBUG,
-						"httpread got content(%p)", h);
+				wpa_printf(MSG_DEBUG,
+					   "httpread got content(%p)", h);
 				goto got_file;
 			}
 			if (nread <= 0)
@@ -601,6 +618,11 @@
 				ncopy = nread;
 			}
 			/* Note: should never be 0 */
+			if (ncopy < 0) {
+				wpa_printf(MSG_DEBUG,
+					   "httpread: Invalid ncopy=%d", ncopy);
+				goto bad;
+			}
 			if (ncopy > nread)
 				ncopy = nread;
 			os_memcpy(bbp, rbp, ncopy);
@@ -635,10 +657,9 @@
 				if (c == '\n') {
 					h->trailer_state = trailer_line_begin;
 					h->in_trailer = 0;
-					if (httpread_debug >= 10)
-						wpa_printf(
-							MSG_DEBUG,
-							"httpread got content(%p)", h);
+					wpa_printf(MSG_DEBUG,
+						   "httpread got content(%p)",
+						   h);
 					h->got_body = 1;
 					goto got_file;
 				}
@@ -666,13 +687,14 @@
 	return;
 
 get_more:
+	wpa_printf(MSG_DEBUG, "httpread: get more (%p)", h);
 	return;
 
 got_file:
-	if (httpread_debug >= 10)
-		wpa_printf(MSG_DEBUG,
-			   "httpread got file %d bytes type %d",
-			   h->body_nbytes, h->hdr_type);
+	wpa_printf(MSG_DEBUG, "httpread got file %d bytes type %d",
+		   h->body_nbytes, h->hdr_type);
+	wpa_hexdump_ascii(MSG_MSGDUMP, "httpread: body",
+			  h->body, h->body_nbytes);
 	/* Null terminate for convenience of some applications */
 	if (h->body)
 		h->body[h->body_nbytes] = 0; /* null terminate */