mirror of
https://github.com/SCST-project/scst.git
synced 2026-08-17 04:36:22 +00:00
scst: Fix parsing of CDB control byte
SCST_GET_CDB_LEN() returns 0 for vendor-specific opcodes such as:
0xD1 READ DYN RUNTIME ATT
0xD2 WRITE DYN RUNTIME ATTR
0xE7 INIT ELEMENT STATUS WRANGE
This causes scst_set_cmd_from_cdb_info() to check cdb[-1] for the
control byte, causing an out-of-bounds array read.
- Move the parsing of the control byte after get_cdb_info() since that
may set the CDB length to a known value.
- If the CDB length is still unknown, then assume the control byte is
0 without accessing the CDB.
- Check for variable-length CDBs in scst_set_cmd_from_cdb_info() rather
than using the wrong control byte and then overriding it in
get_cdb_info_var_len(). This is necessary because the override would
no longer work after the change above.
Also, the following code doesn't work:
#define CONTROL_BYTE_NACA_BIT 0x04
unsigned int cmd_naca:1;
cmd_naca = (control & CONTROL_BYTE_NACA_BIT);
The result will always be 0. Use this instead:
cmd_naca = !!(control & CONTROL_BYTE_NACA_BIT);
(cmd_linked happened to work because CONTROL_BYTE_LINK_BIT is 0x01, but
apply the same fix there also for consistency).
Signed-off-by: Tony Battersby <tonyb@cybernetics.com>
This commit is contained in:
committed by
Gleb Chesnokov
parent
63f2375fe4
commit
f9de3f4169
+9
-5
@@ -11941,8 +11941,6 @@ static int scst_set_cmd_from_cdb_info(struct scst_cmd *cmd,
|
||||
int res;
|
||||
|
||||
cmd->cdb_len = SCST_GET_CDB_LEN(cmd->cdb[0]);
|
||||
cmd->cmd_naca = (cmd->cdb[cmd->cdb_len - 1] & CONTROL_BYTE_NACA_BIT);
|
||||
cmd->cmd_linked = (cmd->cdb[cmd->cdb_len - 1] & CONTROL_BYTE_LINK_BIT);
|
||||
cmd->op_name = ptr->info_op_name;
|
||||
cmd->data_direction = ptr->info_data_direction;
|
||||
cmd->op_flags = ptr->info_op_flags | SCST_INFO_VALID;
|
||||
@@ -11952,6 +11950,15 @@ static int scst_set_cmd_from_cdb_info(struct scst_cmd *cmd,
|
||||
cmd->len_len = ptr->info_len_len;
|
||||
cmd->log2_max_buf_len = ptr->log2_max_buf_len;
|
||||
res = (*ptr->get_cdb_info)(cmd, ptr);
|
||||
|
||||
/* get_cdb_info() may override cdb_len, so do this after */
|
||||
if (likely(cmd->cdb_len != 0)) {
|
||||
unsigned int control = (cmd->cdb[0] == 0x7F) ? cmd->cdb[1] :
|
||||
cmd->cdb[cmd->cdb_len - 1];
|
||||
cmd->cmd_naca = !!(control & CONTROL_BYTE_NACA_BIT);
|
||||
cmd->cmd_linked = !!(control & CONTROL_BYTE_LINK_BIT);
|
||||
}
|
||||
|
||||
if (!cmd->log2_max_buf_len ||
|
||||
cmd->bufflen <= (1U << cmd->log2_max_buf_len))
|
||||
return res;
|
||||
@@ -12047,9 +12054,6 @@ static int get_cdb_info_var_len(struct scst_cmd *cmd,
|
||||
|
||||
res = scst_set_cmd_from_cdb_info(cmd, ptr);
|
||||
|
||||
cmd->cmd_naca = (cmd->cdb[1] & CONTROL_BYTE_NACA_BIT);
|
||||
cmd->cmd_linked = (cmd->cdb[1] & CONTROL_BYTE_LINK_BIT);
|
||||
|
||||
out:
|
||||
TRACE_EXIT_RES(res);
|
||||
return res;
|
||||
|
||||
Reference in New Issue
Block a user