CVE-2013-2850: Improper Restriction of Operations within the Bounds of a Memory Buffer (CWE-119)
value: Heap-based buffer overflow in the iscsi_add_notunderstood_response function in drivers/target/iscsi/iscsi_target_parameters.c in the iSCSI target subsystem in the Linux kernel through 3.9.4 allows remote attackers to cause a denial of service (memory corruption and OOPS) or possibly execute arbitrary code via a long key that is not properly handled during construction of an error-response packet.
CWE description: The product performs operations on a memory buffer, but it reads from or writes to a memory location outside the buffer's intended boundary. This may result in read or write operations on unexpected memory locations that could be linked to other variables, data structures, or internal program data.
Published: 2013-06-07T14:03Z
Repository: https://github.com/torvalds/linux
Language: C
Files changed: drivers/target/iscsi/iscsi_target_parameters.c, drivers/target/iscsi/iscsi_target_parameters.h
Commit date: 2013-05-30 18:07:54 -0700
Commit message: iscsi-target: fix heap buffer overflow on error

If a key was larger than 64 bytes, as checked by iscsi_check_key(), the
error response packet, generated by iscsi_add_notunderstood_response(),
would still attempt to copy the entire key into the packet, overflowing
the structure on the heap.

Remote preauthentication kernel memory corruption was possible if a
target was configured and listening on the network.

CVE-2013-2850

Signed-off-by: Kees Cook <keescook@chromium.org>
Cc: stable@vger.kernel.org
Signed-off-by: Nicholas Bellinger <nab@linux-iscsi.org>

Diff: diff --git a/drivers/target/iscsi/iscsi_target_parameters.c b/drivers/target/iscsi/iscsi_target_parameters.c
index c2185fc3113683..e38222191a33b7 100644
--- a/drivers/target/iscsi/iscsi_target_parameters.c
+++ b/drivers/target/iscsi/iscsi_target_parameters.c
@@ -756,13 +756,13 @@ static int iscsi_add_notunderstood_response(
 			" struct iscsi_extra_response.\n");
 		return -1;
 	}
 	INIT_LIST_HEAD(&extra_response->er_list);
 
-	strncpy(extra_response->key, key, strlen(key) + 1);
-	strncpy(extra_response->value, NOTUNDERSTOOD,
-			strlen(NOTUNDERSTOOD) + 1);
+	strlcpy(extra_response->key, key, sizeof(extra_response->key));
+	strlcpy(extra_response->value, NOTUNDERSTOOD,
+		sizeof(extra_response->value));
 
 	list_add_tail(&extra_response->er_list,
 			&param_list->extra_response_list);
 	return 0;
 }
@@ -1627,12 +1627,10 @@ int iscsi_decode_text_input(
 
 		pr_debug("Got key: %s=%s\n", key, value);
 
 		if (phase & PHASE_SECURITY) {
 			if (iscsi_check_for_auth_key(key) > 0) {
-				char *tmpptr = key + strlen(key);
-				*tmpptr = '=';
 				kfree(tmpbuf);
 				return 1;
 			}
 		}
 
diff --git a/drivers/target/iscsi/iscsi_target_parameters.h b/drivers/target/iscsi/iscsi_target_parameters.h
index 915b067985059b..a47046a752aac7 100644
--- a/drivers/target/iscsi/iscsi_target_parameters.h
+++ b/drivers/target/iscsi/iscsi_target_parameters.h
@@ -1,10 +1,12 @@
 #ifndef ISCSI_PARAMETERS_H
 #define ISCSI_PARAMETERS_H
 
+#include <scsi/iscsi_proto.h>
+
 struct iscsi_extra_response {
-	char key[64];
+	char key[KEY_MAXLEN];
 	char value[32];
 	struct list_head er_list;
 } ____cacheline_aligned;
 
 struct iscsi_param {

Vulnerable code: 	strncpy(extra_response->key, key, strlen(key) + 1);
	strncpy(extra_response->value, NOTUNDERSTOOD,
			strlen(NOTUNDERSTOOD) + 1);
				char *tmpptr = key + strlen(key);
				*tmpptr = '=';
	char key[64];
Fixed code: 	strlcpy(extra_response->key, key, sizeof(extra_response->key));
	strlcpy(extra_response->value, NOTUNDERSTOOD,
		sizeof(extra_response->value));
#include <scsi/iscsi_proto.h>

	char key[KEY_MAXLEN];