[PATCH 4/7] crash bug in spc_mode_sense
Ronnie Sahlberg
ronniesahlberg
Fri May 2 14:36:54 CEST 2008
If an initiator/application is requesting mode_sense and specifying a very
small allocation_length (2,8 or so bytes) but the mode page itself
is big, then the memcpy() in build_mode_page() will overwrite other memory
and cause tgtd to crash.
be more careful when writing to the data buffer.
Signed-off-by: Ronnie Sahlberg <ronniesahlberg at gmail.com>
---
usr/spc.c | 63 ++++++++++++++++++++++++++++++++++--------------------------
1 files changed, 36 insertions(+), 27 deletions(-)
diff --git a/usr/spc.c b/usr/spc.c
index e3e4d98..6707778 100644
--- a/usr/spc.c
+++ b/usr/spc.c
@@ -335,22 +335,28 @@ int spc_test_unit(int host_no, struct scsi_cmd *cmd)
*
* Returns number of bytes copied.
*/
-static int build_mode_page(uint8_t *data, struct mode_pg *pg, int update)
+static uint8_t *build_mode_page(uint8_t *data, uint8_t *p, int alloc_len,
+ struct mode_pg *pg)
{
- uint8_t *p;
- int len;
+ int i;
+
+ if (alloc_len > (p-data))
+ *p = pg->pcode;
+ p++;
+
+
+ if (alloc_len > (p-data))
+ *p = pg->pcode_size;
+ p++;
+
- len = pg->pcode_size;
- if (update) {
- data[0] = pg->pcode;
- data[1] = len;
+ for (i = 0; i < pg->pcode_size; i++) {
+ if (alloc_len > (p-data))
+ *p = pg->mode_data[i];
+ p++;
}
- p = &data[2];
- len += 2;
- if (update)
- memcpy(p, pg->mode_data, pg->pcode_size);
- return len;
+ return p;
}
/**
@@ -362,12 +368,13 @@ static int build_mode_page(uint8_t *data, struct
mode_pg *pg, int update)
*/
int spc_mode_sense(int host_no, struct scsi_cmd *cmd)
{
- int len = 0;
uint8_t *data = NULL, *scb, mode6, dbd, pcode, subpcode;
+ uint8_t *p;
uint16_t alloc_len;
unsigned char key = ILLEGAL_REQUEST;
uint16_t asc = ASC_INVALID_FIELD_IN_CDB;
struct mode_pg *pg;
+ int i;
scb = cmd->scb;
mode6 = (scb[0] == 0x1a);
@@ -383,10 +390,10 @@ int spc_mode_sense(int host_no, struct scsi_cmd *cmd)
if (mode6) {
alloc_len = scb[4];
- len = 4;
+ p = &data[4];
} else {
alloc_len = (scb[7] << 8) + scb[8];
- len = 8;
+ p = &data[8];
}
if (scsi_get_in_length(cmd) < alloc_len)
@@ -394,10 +401,11 @@ int spc_mode_sense(int host_no, struct scsi_cmd *cmd)
memset(data, 0, alloc_len);
if (!dbd) {
- if (alloc_len >= len)
- memcpy(data + len, cmd->dev->mode_block_descriptor,
- BLOCK_DESCRIPTOR_LEN);
- len += BLOCK_DESCRIPTOR_LEN;
+ for (i = 0; i < BLOCK_DESCRIPTOR_LEN; i++) {
+ if (alloc_len > (p-data))
+ *p = cmd->dev->mode_block_descriptor[i];
+ p++;
+ }
}
if (pcode == 0x3f) {
@@ -405,25 +413,26 @@ int spc_mode_sense(int host_no, struct scsi_cmd *cmd)
for (i = 0; i < ARRAY_SIZE(cmd->dev->mode_pgs); i++) {
pg = cmd->dev->mode_pgs[i];
if (pg)
- len += build_mode_page(data + len, pg,
- alloc_len >= len);
+ p = build_mode_page(data, p, alloc_len, pg);
}
} else {
pg = cmd->dev->mode_pgs[pcode];
if (!pg)
goto sense;
- len += build_mode_page(data + len, pg, alloc_len >= len);
+ p = build_mode_page(data, p, alloc_len, pg);
}
if (mode6) {
- data[0] = len - 1;
- data[3] = dbd ? 0 : BLOCK_DESCRIPTOR_LEN;
+ data[0] = (p - data) - 1;
+ if (alloc_len > 3)
+ data[3] = dbd ? 0 : BLOCK_DESCRIPTOR_LEN;
} else {
- *(uint16_t *)(data) = __cpu_to_be16(len - 2);
- data[7] = dbd ? 0 : BLOCK_DESCRIPTOR_LEN;
+ *(uint16_t *)(data) = __cpu_to_be16((p - data)-2);
+ if (alloc_len > 7)
+ data[7] = dbd ? 0 : BLOCK_DESCRIPTOR_LEN;
}
- scsi_set_in_resid_by_actual(cmd, len);
+ scsi_set_in_resid_by_actual(cmd, p - data);
return SAM_STAT_GOOD;
sense:
scsi_set_in_resid_by_actual(cmd, 0);
--
1.5.5
More information about the stgt
mailing list