Skip to content

Commit 091719c

Browse files
abattersbymartinkpetersen
authored andcommitted
scsi: qla2xxx: target: Fix invalid memory access with big CDBs
struct atio7_fcp_cmnd is a variable-length data structure because of add_cdb_len, but it is embedded in struct atio_from_isp and copied around like a fixed-length data structure. For big CDBs > 16 bytes, get_datalen_for_atio() called on a fixed-length copy of the atio will access invalid memory. In some cases this can be fixed by moving the atio to the end of the data structure and using a variable-length allocation. In other cases such as allocating struct qla_tgt_cmd, the fixed-length data structures are preallocated for speed, so in the case that add_cdb_len != 0, allocate a separate buffer for the CDB. Also add memcpy_atio() as a safeguard against invalid memory accesses. Signed-off-by: Tony Battersby <tonyb@cybernetics.com> Link: https://patch.msgid.link/306a9d0b-3c89-42fc-a69c-eebca8171347@cybernetics.com Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
1 parent 3d56983 commit 091719c

2 files changed

Lines changed: 81 additions & 9 deletions

File tree

drivers/scsi/qla2xxx/qla_target.c

Lines changed: 76 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,10 @@ static void qlt_queue_unknown_atio(scsi_qla_host_t *vha,
210210
struct qla_tgt_sess_op *u;
211211
struct qla_tgt *tgt = vha->vha_tgt.qla_tgt;
212212
unsigned long flags;
213+
unsigned int add_cdb_len = 0;
214+
215+
/* atio must be the last member of qla_tgt_sess_op for add_cdb_len */
216+
BUILD_BUG_ON(offsetof(struct qla_tgt_sess_op, atio) + sizeof(u->atio) != sizeof(*u));
213217

214218
if (tgt->tgt_stop) {
215219
ql_dbg(ql_dbg_async, vha, 0x502c,
@@ -218,12 +222,17 @@ static void qlt_queue_unknown_atio(scsi_qla_host_t *vha,
218222
goto out_term;
219223
}
220224

221-
u = kzalloc(sizeof(*u), GFP_ATOMIC);
225+
if (atio->u.raw.entry_type == ATIO_TYPE7 &&
226+
atio->u.isp24.fcp_cmnd.task_mgmt_flags == 0)
227+
add_cdb_len =
228+
((unsigned int) atio->u.isp24.fcp_cmnd.add_cdb_len) * 4;
229+
230+
u = kzalloc(sizeof(*u) + add_cdb_len, GFP_ATOMIC);
222231
if (u == NULL)
223232
goto out_term;
224233

225234
u->vha = vha;
226-
memcpy(&u->atio, atio, sizeof(*atio));
235+
memcpy(&u->atio, atio, sizeof(*atio) + add_cdb_len);
227236
INIT_LIST_HEAD(&u->cmd_list);
228237

229238
spin_lock_irqsave(&vha->cmd_list_lock, flags);
@@ -3831,6 +3840,13 @@ void qlt_free_cmd(struct qla_tgt_cmd *cmd)
38313840
qlt_decr_num_pend_cmds(cmd->vha);
38323841

38333842
BUG_ON(cmd->sg_mapped);
3843+
3844+
if (unlikely(cmd->cdb != &cmd->atio.u.isp24.fcp_cmnd.cdb[0])) {
3845+
kfree(cmd->cdb);
3846+
cmd->cdb = &cmd->atio.u.isp24.fcp_cmnd.cdb[0];
3847+
cmd->cdb_len = 16;
3848+
}
3849+
38343850
cmd->jiffies_at_free = get_jiffies_64();
38353851

38363852
if (!sess || !sess->se_sess) {
@@ -4130,7 +4146,6 @@ static void __qlt_do_work(struct qla_tgt_cmd *cmd)
41304146
struct qla_hw_data *ha = vha->hw;
41314147
struct fc_port *sess = cmd->sess;
41324148
struct atio_from_isp *atio = &cmd->atio;
4133-
unsigned char *cdb;
41344149
unsigned long flags;
41354150
uint32_t data_length;
41364151
int ret, fcp_task_attr, data_dir, bidi = 0;
@@ -4146,7 +4161,6 @@ static void __qlt_do_work(struct qla_tgt_cmd *cmd)
41464161
goto out_term;
41474162
}
41484163

4149-
cdb = &atio->u.isp24.fcp_cmnd.cdb[0];
41504164
cmd->se_cmd.tag = le32_to_cpu(atio->u.isp24.exchange_addr);
41514165

41524166
if (atio->u.isp24.fcp_cmnd.rddata &&
@@ -4164,7 +4178,7 @@ static void __qlt_do_work(struct qla_tgt_cmd *cmd)
41644178
atio->u.isp24.fcp_cmnd.task_attr);
41654179
data_length = get_datalen_for_atio(atio);
41664180

4167-
ret = ha->tgt.tgt_ops->handle_cmd(vha, cmd, cdb, data_length,
4181+
ret = ha->tgt.tgt_ops->handle_cmd(vha, cmd, cmd->cdb, data_length,
41684182
fcp_task_attr, data_dir, bidi);
41694183
if (ret != 0)
41704184
goto out_term;
@@ -4185,6 +4199,11 @@ static void __qlt_do_work(struct qla_tgt_cmd *cmd)
41854199
qlt_send_term_exchange(qpair, NULL, &cmd->atio, 1);
41864200

41874201
qlt_decr_num_pend_cmds(vha);
4202+
if (unlikely(cmd->cdb != &cmd->atio.u.isp24.fcp_cmnd.cdb[0])) {
4203+
kfree(cmd->cdb);
4204+
cmd->cdb = &cmd->atio.u.isp24.fcp_cmnd.cdb[0];
4205+
cmd->cdb_len = 16;
4206+
}
41884207
cmd->vha->hw->tgt.tgt_ops->rel_cmd(cmd);
41894208
spin_unlock_irqrestore(qpair->qp_lock_ptr, flags);
41904209

@@ -4308,18 +4327,43 @@ static void qlt_assign_qpair(struct scsi_qla_host *vha,
43084327
cmd->se_cmd.cpuid = h->cpuid;
43094328
}
43104329

4330+
/*
4331+
* Safely make a fixed-length copy of a variable-length atio by truncating the
4332+
* CDB if necessary.
4333+
*/
4334+
static void memcpy_atio(struct atio_from_isp *dst,
4335+
const struct atio_from_isp *src)
4336+
{
4337+
int len;
4338+
4339+
memcpy(dst, src, sizeof(*dst));
4340+
4341+
/*
4342+
* If the CDB was truncated, prevent get_datalen_for_atio() from
4343+
* accessing invalid memory.
4344+
*/
4345+
len = src->u.isp24.fcp_cmnd.add_cdb_len;
4346+
if (unlikely(len != 0)) {
4347+
dst->u.isp24.fcp_cmnd.add_cdb_len = 0;
4348+
memcpy(&dst->u.isp24.fcp_cmnd.add_cdb[0],
4349+
&src->u.isp24.fcp_cmnd.add_cdb[len * 4],
4350+
4);
4351+
}
4352+
}
4353+
43114354
static struct qla_tgt_cmd *qlt_get_tag(scsi_qla_host_t *vha,
43124355
struct fc_port *sess,
43134356
struct atio_from_isp *atio)
43144357
{
43154358
struct qla_tgt_cmd *cmd;
4359+
int add_cdb_len;
43164360

43174361
cmd = vha->hw->tgt.tgt_ops->get_cmd(sess);
43184362
if (!cmd)
43194363
return NULL;
43204364

43214365
cmd->cmd_type = TYPE_TGT_CMD;
4322-
memcpy(&cmd->atio, atio, sizeof(*atio));
4366+
memcpy_atio(&cmd->atio, atio);
43234367
INIT_LIST_HEAD(&cmd->sess_cmd_list);
43244368
cmd->state = QLA_TGT_STATE_NEW;
43254369
cmd->tgt = vha->vha_tgt.qla_tgt;
@@ -4339,6 +4383,29 @@ static struct qla_tgt_cmd *qlt_get_tag(scsi_qla_host_t *vha,
43394383
cmd->vp_idx = vha->vp_idx;
43404384
cmd->edif = sess->edif.enable;
43414385

4386+
cmd->cdb = &cmd->atio.u.isp24.fcp_cmnd.cdb[0];
4387+
cmd->cdb_len = 16;
4388+
4389+
/*
4390+
* NOTE: memcpy_atio() set cmd->atio.u.isp24.fcp_cmnd.add_cdb_len to 0,
4391+
* so use the original value here.
4392+
*/
4393+
add_cdb_len = atio->u.isp24.fcp_cmnd.add_cdb_len;
4394+
if (unlikely(add_cdb_len != 0)) {
4395+
int cdb_len = 16 + add_cdb_len * 4;
4396+
u8 *cdb;
4397+
4398+
cdb = kmalloc(cdb_len, GFP_ATOMIC);
4399+
if (unlikely(!cdb)) {
4400+
vha->hw->tgt.tgt_ops->free_cmd(cmd);
4401+
return NULL;
4402+
}
4403+
/* CAUTION: copy CDB from atio not cmd->atio */
4404+
memcpy(cdb, atio->u.isp24.fcp_cmnd.cdb, cdb_len);
4405+
cmd->cdb = cdb;
4406+
cmd->cdb_len = cdb_len;
4407+
}
4408+
43424409
return cmd;
43434410
}
43444411

@@ -5486,13 +5553,15 @@ qlt_alloc_qfull_cmd(struct scsi_qla_host *vha,
54865553

54875554
qlt_incr_num_pend_cmds(vha);
54885555
INIT_LIST_HEAD(&cmd->cmd_list);
5489-
memcpy(&cmd->atio, atio, sizeof(*atio));
5556+
memcpy_atio(&cmd->atio, atio);
54905557

54915558
cmd->tgt = vha->vha_tgt.qla_tgt;
54925559
cmd->vha = vha;
54935560
cmd->reset_count = ha->base_qpair->chip_reset;
54945561
cmd->q_full = 1;
54955562
cmd->qpair = ha->base_qpair;
5563+
cmd->cdb = &cmd->atio.u.isp24.fcp_cmnd.cdb[0];
5564+
cmd->cdb_len = 16;
54965565

54975566
if (qfull) {
54985567
cmd->q_full = 1;

drivers/scsi/qla2xxx/qla_target.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -830,11 +830,13 @@ struct qla_tgt {
830830
struct qla_tgt_sess_op {
831831
struct scsi_qla_host *vha;
832832
uint32_t chip_reset;
833-
struct atio_from_isp atio;
834833
struct work_struct work;
835834
struct list_head cmd_list;
836835
bool aborted;
837836
struct rsp_que *rsp;
837+
838+
struct atio_from_isp atio;
839+
/* DO NOT ADD ANYTHING ELSE HERE - atio must be last member */
838840
};
839841

840842
enum trace_flags {
@@ -925,8 +927,9 @@ struct qla_tgt_cmd {
925927
uint8_t scsi_status, sense_key, asc, ascq;
926928

927929
struct crc_context *ctx;
928-
const uint8_t *cdb;
930+
uint8_t *cdb;
929931
uint64_t lba;
932+
int cdb_len;
930933
uint16_t a_guard, e_guard, a_app_tag, e_app_tag;
931934
uint32_t a_ref_tag, e_ref_tag;
932935
#define DIF_BUNDL_DMA_VALID 1

0 commit comments

Comments
 (0)