--- a/sys/dev/raid/tws/tws_user.c +++ b/sys/dev/raid/tws/tws_user.c @@ -126,10 +126,26 @@ tws_passthru(struct tws_softc *sc, void *buf) memcpy(&req->cmd_pkt->cmd, &ubuf->cmd_pkt.cmd, sizeof(struct tws_command_apache)); if ( GET_OPCODE(req->cmd_pkt->cmd.pkt_a.res__opcode) == TWS_FW_CMD_EXECUTE_SCSI ) { lun4 = req->cmd_pkt->cmd.pkt_a.lun_l4__req_id & 0xF000; req->cmd_pkt->cmd.pkt_a.lun_l4__req_id = lun4 | req->request_id; } else { + /* + * The generic path writes the SGL at + * (u_int32_t *)gcmd + gcmd->size + * (tws_cam.c:1035) with up to max_sg_elements descriptors. gcmd->size + * is caller-controlled and previously unvalidated: with size=255 up + * to 736 bytes of descriptors are written ~860 bytes past the end of + * this request's 1024-byte command packet into neighboring requests + * of the dma_mem pool. Keep the SGL inside this packet. + */ + size_t ent = (sc->is64bit && !tws_use_32bit_sgls) ? + sizeof(struct tws_sg_desc64) : + sizeof(struct tws_sg_desc32); + u_int max_sgls = (sc->is64bit && !tws_use_32bit_sgls) ? + TWS_MAX_64BIT_SG_ELEMENTS : TWS_MAX_32BIT_SG_ELEMENTS; + size_t off = sizeof(struct tws_command_header) + + 4 * req->cmd_pkt->cmd.pkt_g.generic.size; + if ( off + max_sgls * ent > sizeof(struct tws_command_packet) ) { + req->state = TWS_REQ_STATE_FREE; + if ( sc->chan ) { sc->chan = 0; wakeup((void *)&sc->chan); } + return(EINVAL); + } req->cmd_pkt->cmd.pkt_g.generic.request_id = (u_int8_t) req->request_id; }