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;