File iscsitarget-isns-bounds-checking of Package iscsitarget
From a1fba2354c505aaba8ad01953f2a5669d66da5c9 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] 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.
Signed-off-by: Ross Walker
git-svn-id: https://iscsitarget.svn.sourceforge.net/svnroot/iscsitarget/trunk@367 48a34bb2-7106-0410-bc49-8aa7273d22a1
diff --git a/usr/isns.c b/usr/isns.c
index b2d038e..3c0525d 100644
--- a/usr/isns.c
+++ b/usr/isns.c
@@ -442,6 +442,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);
}
}
@@ -595,18 +596,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;
}
@@ -666,24 +685,45 @@ 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;
+
snprintf(ini->name, sizeof(ini->name), "%s",
name);
+
insque(&ini->ilist, &target->isns_head);
} else
name = NULL;