[PATCH 1/4] fix alloc len vs buffer len checks and safeguard memcpy in spc_pr_read_reservation()

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Alexander Nezhinsky <nezhinsky@xxxxxxxxx>

SPC-3, 6.13.3.2, alloc len must be at least 8 bytes,
when no reservation is held, additional len field should be 0, total data-in len is 8;
when there is reservation, additional len should be 16, total buffer len is 24.

make sure that setting fields in data-in buffer don't pass its boundary.

Signed-off-by: Alexander Nezhinsky <nezhinsky@xxxxxxxxx>
---
 usr/spc.c |   43 ++++++++++++++++++++++---------------------
 1 file changed, 22 insertions(+), 21 deletions(-)

diff --git a/usr/spc.c b/usr/spc.c
index 9fb5a6d..0289730 100644
--- a/usr/spc.c
+++ b/usr/spc.c
@@ -928,46 +928,47 @@ sense:
 
 static int spc_pr_read_reservation(int host_no, struct scsi_cmd *cmd)
 {
-	uint16_t asc = ASC_INVALID_FIELD_IN_CDB;
-	uint8_t key = ILLEGAL_REQUEST;
+	uint32_t alloc_len, add_len, avail_len, actual_len;
 	struct registration *reg;
-	uint16_t len;
-	uint8_t *buf;
 	uint64_t res_key;
+	uint8_t *buf;
+	uint16_t asc = ASC_INVALID_FIELD_IN_CDB;
+	uint8_t key = ILLEGAL_REQUEST;
 
-	reg = cmd->dev->pr_holder;
-
-	if (reg)
-		len = 24;
-	else
-		len = 8;
-
-	if (get_unaligned_be16(cmd->scb + 7) < len)
+	alloc_len = (uint32_t)get_unaligned_be16(&cmd->scb[7]);
+	if (alloc_len < 8)
 		goto sense;
 
-	if (scsi_get_in_length(cmd) < len)
+	if (scsi_get_in_length(cmd) < alloc_len)
 		goto sense;
 
+	reg = cmd->dev->pr_holder;
+	add_len = (reg ? 16 : 0);
+	avail_len = 8 + add_len;
+
 	buf = scsi_get_in_buffer(cmd);
-	memset(buf, 0, len);
+	memset(buf, 0, alloc_len);
 
 	put_unaligned_be32(cmd->dev->prgeneration, &buf[0]);
+	put_unaligned_be32(add_len, &buf[4]); /* additional length */
 
 	if (reg) {
-		put_unaligned_be32(16, &buf[4]);
-
 		if (reg->pr_type == PR_TYPE_WRITE_EXCLUSIVE_ALLREG ||
 		    reg->pr_type == PR_TYPE_EXCLUSIVE_ACCESS_ALLREG)
 			res_key = 0;
 		else
 			res_key = reg->key;
 
-		put_unaligned_be64(res_key, &buf[8]);
-		buf[21] = ((reg->pr_scope << 4) & 0xf0) | (reg->pr_type & 0x0f);
-	} else
-		put_unaligned_be32(0, &buf[4]);
+		if (alloc_len > 15)
+			put_unaligned_be64(res_key, &buf[8]);
+		if (alloc_len > 21) {
+			buf[21] = (reg->pr_scope << 4) & 0xf0;
+			buf[21] |= reg->pr_type & 0x0f;
+		}
+	}
 
-	scsi_set_in_resid_by_actual(cmd, len);
+	actual_len = min_t(uint32_t, alloc_len, avail_len);
+	scsi_set_in_resid_by_actual(cmd, actual_len);
 
 	return SAM_STAT_GOOD;
 sense:
-- 
1.7.9.6

--
To unsubscribe from this list: send the line "unsubscribe stgt" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux SCSI]     [Linux RAID]     [Linux Clusters]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]

  Powered by Linux