--- a/sys/dev/raid/tws/tws_cam.c +++ b/sys/dev/raid/tws/tws_cam.c @@ -1031,10 +1031,21 @@ GET_OPCODE(req->cmd_pkt->cmd.pkt_a.res__opcode) != TWS_FW_CMD_EXECUTE_SCSI) || req->type == TWS_GETSET_PARAM_REQ) { + u_int16_t ent_u32; gcmd = &req->cmd_pkt->cmd.pkt_g.generic; + ent_u32 = (req->sc->is64bit && !tws_use_32bit_sgls) ? 4 : 2; + /* + * gcmd->size arrives from the passthrough ioctl and is used as + * the SGL offset (u32 units). Never let the SGL start beyond, + * or overflow, this request's own giga-packet body. + */ + if ((u_int)gcmd->size + (u_int)sgls * ent_u32 > + (sizeof(union tws_command_giga) / 4)) { + req->error_code = TWS_REQ_ERR_INVALID; + return; /* do not submit the command */ + } sgl_ptr = (u_int32_t *)(gcmd) + gcmd->size; - gcmd->size += sgls * - ((req->sc->is64bit && !tws_use_32bit_sgls) ? 4 :2 ); + gcmd->size += sgls * ent_u32; tws_fill_sg_list(req->sc, segs, sgl_ptr, sgls); } else {