File iscsitarget-isns-bounds-checking of Package iscsitarget

From 798be44fe9c5254f7a497fb4e082b27c16421839 Mon Sep 17 00:00:00 2001
From: rswwalker <rswwalker@48a34bb2-7106-0410-bc49-8aa7273d22a1>
Date: Thu, 1 Jul 2010 21:17:35 +0000
Subject: [PATCH] Fix iSNS bounds checking

This patch fixes the iSNS code's bounds checking on SCN packets.
Fixes a couple buffer overflow scenarios per CVE-2010-2221.
Also fixes a memory leak with initiator ACLs.

References: bnc#618574

Signed-off-by: Ross Walker
Signed-off-by: Hannes Reinecke <hare@suse.de>

diff --git a/usr/isns.c b/usr/isns.c
index adc86be..b114b7f 100644
--- a/usr/isns.c
+++ b/usr/isns.c
@@ -438,6 +438,7 @@ static void free_all_acl(struct target *target)
 	while (!list_empty(&target->isns_head)) {
 		ini = list_entry(target->isns_head.q_forw, typeof(*ini), ilist);
 		remque(&ini->ilist);
+		free(ini);
 	}
 }
 
@@ -600,18 +601,36 @@ static char *print_scn_pdu(struct isns_hdr *hdr)
 	while (length) {
 		uint32_t vlen = ntohl(tlv->length);
 
+		if (vlen + sizeof(*tlv) > length)
+			vlen = length - sizeof(*tlv);
+
 		switch (ntohl(tlv->tag)) {
 		case ISNS_ATTR_ISCSI_NAME:
-			log_error("scn name: %u, %s", vlen, (char *) tlv->value);
-			if (!name)
-				name = (char *) tlv->value;
+			if (vlen) {
+				size_t slen = vlen - 1;
+
+				if (slen > ISCSI_NAME_LEN)
+					slen = ISCSI_NAME_LEN;
+
+				*((char *) tlv->value + slen) = 0;
+
+				log_error("scn name: %u, %s", vlen,
+					  (char *) tlv->value);
+
+				if (!name)
+					name = (char *) tlv->value;
+			}
 			break;
 		case ISNS_ATTR_TIMESTAMP:
-/* 			log_error("%u : %u : %" PRIx64, ntohl(tlv->tag), vlen, */
-/* 				  *((uint64_t *) tlv->value)); */
+/*			if (vlen == 8)
+				log_error("%u : %u : %" PRIx64, ntohl(tlv->tag),
+					  vlen, *((uint64_t *) tlv->value));
+*/
 			break;
 		case ISNS_ATTR_ISCSI_SCN_BITMAP:
-			log_error("scn bitmap : %x", *((uint32_t *) tlv->value));
+			if (vlen == 4)
+				log_error("scn bitmap : %x",
+					  *((uint32_t *) tlv->value));
 			break;
 		}
 
@@ -671,19 +690,38 @@ found:
 
 	/* skip status */
 	tlv = (struct isns_tlv *) ((char *) hdr->pdu + 4);
+
+	if (length < 4)
+		goto free_qry_mgmt;
+
 	length -= 4;
 
 	while (length) {
 		uint32_t vlen = ntohl(tlv->length);
 
+		if (vlen + sizeof(*tlv) > length)
+			vlen = length - sizeof(*tlv);
+
 		switch (ntohl(tlv->tag)) {
 		case ISNS_ATTR_ISCSI_NAME:
-			name = (char *) tlv->value;
+			if (vlen) {
+				size_t slen = vlen - 1;
+
+				if (slen > ISCSI_NAME_LEN)
+					slen = ISCSI_NAME_LEN;
+
+				*((char *) tlv->value + slen) = 0;
+
+				name = (char *) tlv->value;
+			} else
+				name = NULL;
 			break;
 		case ISNS_ATTR_ISCSI_NODE_TYPE:
-			if (ntohl(*(tlv->value)) == ISNS_NODE_INITIATOR && name) {
+			if (vlen == 4 && name &&
+			    ntohl(*(tlv->value)) == ISNS_NODE_INITIATOR) {
 				log_error("%s %d: %s", __FUNCTION__, __LINE__,
 					  (char *) name);
+
 				ini = malloc(sizeof(*ini));
 				if (!ini)
 					goto free_qry_mgmt;