TESTS: Add checks for CDB sanity to REPORT SUPPORTED OPCODES

Read all individual opcodes and check that CDB length > 0  and that
CDB[0] Usage Data is 0xFF
This commit is contained in:
Ronnie Sahlberg
2013-05-19 08:18:09 -07:00
parent c9ee8525b2
commit 4df179bfd4
3 changed files with 154 additions and 52 deletions

View File

@@ -760,6 +760,16 @@ struct scsi_report_supported_op_codes {
struct scsi_command_descriptor descriptors[0];
};
struct scsi_report_supported_op_codes_one_command {
uint8_t ctdp;
uint8_t support;
uint8_t cdb_length;
uint8_t cdb_usage_data[16];
/* only present if CTDP==1 */
struct scsi_op_timeout_descriptor to;
};
struct scsi_persistent_reserve_in_read_keys {
uint32_t prgeneration;
uint32_t additional_length;

View File

@@ -812,6 +812,12 @@ scsi_maintenancein_sa(const struct scsi_task *task)
return task->cdb[1];
}
static inline uint8_t
scsi_report_supported_opcodes_options(const struct scsi_task *task)
{
return task->cdb[2] & 0x07;
}
/*
* parse the data in blob and calculate the size of a full maintenancein
* datain structure
@@ -822,7 +828,15 @@ scsi_maintenancein_datain_getfullsize(struct scsi_task *task)
switch (scsi_maintenancein_sa(task)) {
case SCSI_REPORT_SUPPORTED_OP_CODES:
return task_get_uint32(task, 0) + 4;
switch (scsi_report_supported_opcodes_options(task)) {
case SCSI_REPORT_SUPPORTING_OPS_ALL:
return task_get_uint32(task, 0) + 4;
case SCSI_REPORT_SUPPORTING_OPCODE:
case SCSI_REPORT_SUPPORTING_SERVICEACTION:
return 4 +
(task_get_uint8(task, 1) & 0x80) ? 12 : 0 +
task_get_uint16(task, 2);
}
default:
return -1;
}
@@ -835,64 +849,104 @@ static void *
scsi_maintenancein_datain_unmarshall(struct scsi_task *task)
{
struct scsi_report_supported_op_codes *rsoc;
struct scsi_report_supported_op_codes_one_command *rsoc_one;
int len, i;
switch (scsi_maintenancein_sa(task)) {
case SCSI_REPORT_SUPPORTED_OP_CODES:
if (task->datain.size < 4) {
return NULL;
}
len = task_get_uint32(task, 0);
/* len / 8 is not always correct since if CTDP==1 then the
* descriptor is 20 bytes in size intead of 8.
* It doesnt matter here though since it just means we would
* allocate more descriptors at the end of the structure than
* we strictly need. This avoids having to traverse the
* datain buffer twice.
*/
rsoc = scsi_malloc(task,
offsetof(struct scsi_report_supported_op_codes,
descriptors) +
len / 8 * sizeof(struct scsi_command_descriptor));
if (rsoc == NULL) {
return NULL;
}
rsoc->num_descriptors = 0;
i = 4;
while (len >= 8) {
struct scsi_command_descriptor *desc;
desc = &rsoc->descriptors[rsoc->num_descriptors++];
desc->opcode = task_get_uint8(task, i);
desc->sa = task_get_uint16(task, i + 2);
desc->ctdp = !!(task_get_uint8(task, i + 5) & 0x02);
desc->servactv = !!(task_get_uint8(task, i + 5) & 0x01);
desc->cdb_len = task_get_uint16(task, i + 6);
len -= 8;
i += 8;
/* No tiemout description */
if (!desc->ctdp) {
continue;
switch (scsi_report_supported_opcodes_options(task)) {
case SCSI_REPORT_SUPPORTING_OPS_ALL:
if (task->datain.size < 4) {
return NULL;
}
desc->to.descriptor_length =
task_get_uint16(task, i);
desc->to.command_specific =
task_get_uint8(task, i + 3);
desc->to.nominal_processing_timeout =
task_get_uint32(task, i + 4);
desc->to.recommended_timeout =
task_get_uint32(task, i + 8);
len = task_get_uint32(task, 0);
/* len / 8 is not always correct since if CTDP==1 then
* the descriptor is 20 bytes in size intead of 8.
* It doesnt matter here though since it just means
* we would allocate more descriptors at the end of
* the structure than we strictly need. This avoids
* having to traverse the datain buffer twice.
*/
rsoc = scsi_malloc(task,
offsetof(struct scsi_report_supported_op_codes,
descriptors) +
len / 8 * sizeof(struct scsi_command_descriptor));
if (rsoc == NULL) {
return NULL;
}
len -= desc->to.descriptor_length + 2;
i += desc->to.descriptor_length + 2;
rsoc->num_descriptors = 0;
i = 4;
while (len >= 8) {
struct scsi_command_descriptor *desc;
desc = &rsoc->descriptors[rsoc->num_descriptors++];
desc->opcode =
task_get_uint8(task, i);
desc->sa =
task_get_uint16(task, i + 2);
desc->ctdp =
!!(task_get_uint8(task, i + 5) & 0x02);
desc->servactv =
!!(task_get_uint8(task, i + 5) & 0x01);
desc->cdb_len =
task_get_uint16(task, i + 6);
len -= 8;
i += 8;
/* No tiemout description */
if (!desc->ctdp) {
continue;
}
desc->to.descriptor_length =
task_get_uint16(task, i);
desc->to.command_specific =
task_get_uint8(task, i + 3);
desc->to.nominal_processing_timeout =
task_get_uint32(task, i + 4);
desc->to.recommended_timeout =
task_get_uint32(task, i + 8);
len -= desc->to.descriptor_length + 2;
i += desc->to.descriptor_length + 2;
}
return rsoc;
case SCSI_REPORT_SUPPORTING_OPCODE:
case SCSI_REPORT_SUPPORTING_SERVICEACTION:
rsoc_one = scsi_malloc(task, sizeof(struct scsi_report_supported_op_codes_one_command));
if (rsoc_one == NULL) {
return NULL;
}
rsoc_one->ctdp =
!!(task_get_uint8(task, 1) & 0x80);
rsoc_one->support =
task_get_uint8(task, 1) & 0x07;
rsoc_one->cdb_length =
task_get_uint16(task, 2);
if(rsoc_one->cdb_length <= 16) {
memcpy(rsoc_one->cdb_usage_data,
&task->datain.data[4],
rsoc_one->cdb_length);
}
if (rsoc_one->ctdp) {
i = 4 + rsoc_one->cdb_length;
rsoc_one->to.descriptor_length =
task_get_uint16(task, i);
rsoc_one->to.command_specific =
task_get_uint8(task, i + 3);
rsoc_one->to.nominal_processing_timeout =
task_get_uint32(task, i + 4);
rsoc_one->to.recommended_timeout =
task_get_uint32(task, i + 8);
}
return rsoc_one;
}
return rsoc;
};
return NULL;

View File

@@ -30,7 +30,9 @@ test_report_supported_opcodes_one_command(void)
{
int i, ret;
struct scsi_task *rso_task;
struct scsi_task *one_task;
struct scsi_report_supported_op_codes *rsoc;
struct scsi_report_supported_op_codes_one_command *rsoc_one;
logging(LOG_VERBOSE, LOG_BLANK_LINE);
logging(LOG_VERBOSE, "Test READ_SUPPORTED_OPCODES reading one-command");
@@ -56,7 +58,7 @@ test_report_supported_opcodes_one_command(void)
CU_ASSERT_NOT_EQUAL(rsoc, NULL);
logging(LOG_VERBOSE, "Verify read one-command for all supported "
logging(LOG_VERBOSE, "Verify read one-command works for all supported "
"opcodes");
for (i = 0; i < rsoc->num_descriptors; i++) {
logging(LOG_VERBOSE, "Check opcode:0x%02x ServiceAction:0x%02x",
@@ -107,5 +109,41 @@ test_report_supported_opcodes_one_command(void)
CU_ASSERT_EQUAL(ret, 0);
}
logging(LOG_VERBOSE, "Verify read one-command CDB looks sane");
for (i = 0; i < rsoc->num_descriptors; i++) {
logging(LOG_VERBOSE, "Check CDB for opcode:0x%02x "
"ServiceAction:0x%02x",
rsoc->descriptors[i].opcode,
rsoc->descriptors[i].sa);
ret = report_supported_opcodes(
iscsic, tgt_lun,
0,
rsoc->descriptors[i].servactv ?
SCSI_REPORT_SUPPORTING_SERVICEACTION :
SCSI_REPORT_SUPPORTING_OPCODE,
rsoc->descriptors[i].opcode,
rsoc->descriptors[i].sa,
65535, &one_task);
logging(LOG_VERBOSE, "Unmarshall the DATA-IN buffer");
rsoc_one = scsi_datain_unmarshall(one_task);
CU_ASSERT_NOT_EQUAL(rsoc_one, NULL);
logging(LOG_VERBOSE, "Verify CDB length is not 0");
CU_ASSERT_NOT_EQUAL(rsoc_one->cdb_length, 0);
if (rsoc_one->cdb_length != 0) {
logging(LOG_NORMAL, "[FAILED] CDB length is 0");
}
logging(LOG_VERBOSE, "Verify CDB[0] Usage Data is 0xFF");
CU_ASSERT_EQUAL(rsoc_one->cdb_usage_data[0], 0xff);
if (rsoc_one->cdb_usage_data[0] != 0xff) {
logging(LOG_NORMAL, "[FAILED] CDB[0] Usage Data is "
"not 0xFF");
}
}
scsi_free_scsi_task(rso_task);
}