@@ -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+
43114354static 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 ;
0 commit comments