Blame SOURCES/0029-rework-login-and-discovery-code-to-avoid-strlen-beyond-end-of-data.patch

a66d21
rework login and discovery code to avoid strlen beyond end of data
a66d21
a66d21
Message-id: <1383729402-27559-11-git-send-email-pbonzini@redhat.com>
a66d21
Patchwork-id: 55505
a66d21
O-Subject: [PATCH 10/11] rework login and discovery code to avoid strlen beyond end of data
a66d21
Bugzilla: 1026820
a66d21
RH-Acked-by: Miroslav Rezanina <mrezanin@redhat.com>
a66d21
RH-Acked-by: Orit Wasserman <owasserm@redhat.com>
a66d21
RH-Acked-by: Stefan Hajnoczi <stefanha@redhat.com>
a66d21
a66d21
Checking for the presence of the NUL character should be done
a66d21
without accessing beyond the PDU datain.  Use memchr instead
a66d21
of strlen, and compute the length only if a NUL character is
a66d21
actually there.
a66d21
a66d21
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
a66d21
(cherry picked from commit bfde49756524bd3748234dc6dfa8015e37176e9b)
a66d21
a66d21
Conflicts:
a66d21
	lib/login.c
a66d21
---
a66d21
 lib/discovery.c | 31 ++++++++++++++++++++-----------
a66d21
 lib/login.c     | 32 +++++++++++++++++++++-----------
a66d21
 2 files changed, 41 insertions(+), 22 deletions(-)
a66d21
diff --git a/lib/discovery.c b/lib/discovery.c
a66d21
index 1ddf8ef..7396e71 100644
a66d21
--- a/lib/discovery.c
a66d21
+++ b/lib/discovery.c
a66d21
@@ -112,25 +112,34 @@ iscsi_process_text_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu,
a66d21
 			      pdu->private_data);
a66d21
 		return -1;
a66d21
 	}
a66d21
+	if (size == 0) {
a66d21
+		iscsi_set_error(iscsi, "size == 0 when parsing "
a66d21
+				"discovery data");
a66d21
+		pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL,
a66d21
+			      pdu->private_data);
a66d21
+		return -1;
a66d21
+	}
a66d21
 
a66d21
-	while (size > 0) {
a66d21
+	do {
a66d21
+		unsigned char *end;
a66d21
 		int len;
a66d21
 
a66d21
-		len = strlen((char *)ptr);
a66d21
-
a66d21
-		if (len == 0) {
a66d21
-			break;
a66d21
-		}
a66d21
-
a66d21
-		if (len > size) {
a66d21
-			iscsi_set_error(iscsi, "len > size when parsing "
a66d21
-					"discovery data %d>%d", len, size);
a66d21
+		end = memchr(ptr, 0, size);
a66d21
+		if (end == NULL) {
a66d21
+			iscsi_set_error(iscsi, "NUL not found after offset %td "
a66d21
+					"when parsing discovery data",
a66d21
+					ptr - in->data);
a66d21
 			pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL,
a66d21
 				      pdu->private_data);
a66d21
 			iscsi_free_discovery_addresses(iscsi, targets);
a66d21
 			return -1;
a66d21
 		}
a66d21
 
a66d21
+		len = end - ptr;
a66d21
+		if (len == 0) {
a66d21
+			break;
a66d21
+		}
a66d21
+
a66d21
 		/* parse the strings */
a66d21
 		if (!strncmp((char *)ptr, "TargetName=", 11)) {
a66d21
 			struct iscsi_discovery_address *target;
a66d21
@@ -181,7 +190,7 @@ iscsi_process_text_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu,
a66d21
 
a66d21
 		ptr  += len + 1;
a66d21
 		size -= len + 1;
a66d21
-	}
a66d21
+	} while (size > 0);
a66d21
 
a66d21
 	pdu->callback(iscsi, SCSI_STATUS_GOOD, targets, pdu->private_data);
a66d21
 	iscsi_free_discovery_addresses(iscsi, targets);
a66d21
diff --git a/lib/login.c b/lib/login.c
a66d21
index 22a7408..8b696b0 100644
a66d21
--- a/lib/login.c
a66d21
+++ b/lib/login.c
a66d21
@@ -1000,29 +1000,39 @@ iscsi_process_login_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu,
a66d21
 		iscsi->maxcmdsn = maxcmdsn;
a66d21
 	}
a66d21
 	
a66d21
+	if (size == 0) {
a66d21
+	       iscsi_set_error(iscsi, "size == 0 when parsing "
a66d21
+			       "login data");
a66d21
+	       pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL,
a66d21
+			     pdu->private_data);
a66d21
+	       return -1;
a66d21
+	}
a66d21
+
a66d21
 	/* XXX here we should parse the data returned in case the target
a66d21
 	 * renegotiated some some parameters.
a66d21
 	 *  we should also do proper handshaking if the target is not yet
a66d21
 	 * prepared to transition to the next stage
a66d21
 	 */
a66d21
 
a66d21
-	while (size > 0) {
a66d21
+	do {
a66d21
+		char *end;
a66d21
 		int len;
a66d21
 
a66d21
-		len = strlen(ptr);
a66d21
-
a66d21
-		if (len == 0) {
a66d21
-			break;
a66d21
-		}
a66d21
-
a66d21
-		if (len > size) {
a66d21
-			iscsi_set_error(iscsi, "len > size when parsing "
a66d21
-					"login data %d>%d", len, size);
a66d21
+		end = memchr(ptr, 0, size);
a66d21
+		if (end == NULL) {
a66d21
+			iscsi_set_error(iscsi, "NUL not found after offset %td "
a66d21
+					"when parsing login data",
a66d21
+					(unsigned char *)ptr - in->data);
a66d21
 			pdu->callback(iscsi, SCSI_STATUS_ERROR, NULL,
a66d21
 				      pdu->private_data);
a66d21
 			return -1;
a66d21
 		}
a66d21
 
a66d21
+		len = end - ptr;
a66d21
+		if (len == 0) {
a66d21
+			break;
a66d21
+		}
a66d21
+
a66d21
 		/* parse the strings */
a66d21
 		if (!strncmp(ptr, "TargetAddress=", 14)) {
a66d21
 			strncpy(iscsi->target_address,ptr+14,MAX_STRING_SIZE);
a66d21
@@ -1095,7 +1105,7 @@ iscsi_process_login_reply(struct iscsi_context *iscsi, struct iscsi_pdu *pdu,
a66d21
 
a66d21
 		ptr  += len + 1;
a66d21
 		size -= len + 1;
a66d21
-	}
a66d21
+	} while (size > 0);
a66d21
 
a66d21
 	if (status == SCSI_STATUS_REDIRECT && iscsi->target_address[0]) {
a66d21
 		ISCSI_LOG(iscsi, 2, "target requests redirect to %s",iscsi->target_address);