diff --git a/sys/dev/raid/hptrr/hptrr_osm_bsd.c b/sys/dev/raid/hptrr/hptrr_osm_bsd.c --- a/sys/dev/raid/hptrr/hptrr_osm_bsd.c +++ b/sys/dev/raid/hptrr/hptrr_osm_bsd.c @@ -579,6 +579,16 @@ case INQUIRY: { PINQUIRYDATA inquiryData; + /* The fixed offsets written below reach byte 35 + * (ProductRevisionLevel[3]); require that the caller + * supplied at least that much buffer space. Without + * this check a dxfer_len of 0 (or smaller than the + * fields written) corrupts memory past the data + * buffer. */ + if (ccb->csio.dxfer_len < 36) { + ccb->ccb_h.status = CAM_REQ_ABORTED; + break; + } memset(ccb->csio.data_ptr, 0, ccb->csio.dxfer_len); inquiryData = (PINQUIRYDATA)ccb->csio.data_ptr; @@ -605,6 +615,13 @@ HPT_U8 *rbuf = ccb->csio.data_ptr; HPT_U32 cap; + /* READ_CAPACITY response is exactly 8 bytes; refuse CCBs that + * did not allocate room for the full response. */ + if (ccb->csio.dxfer_len < 8) { + ccb->ccb_h.status = CAM_REQ_ABORTED; + break; + } + if (vd->capacity>0xfffffffful) cap = 0xfffffffful; else @@ -628,6 +645,13 @@ HPT_U8 *rbuf = ccb->csio.data_ptr; HPT_U64 cap = vd->capacity - 1; + /* SERVICE_ACTION_IN(16) read capacity response is 12 bytes; + * refuse CCBs that did not allocate room for the response. */ + if (ccb->csio.dxfer_len < 12) { + ccb->ccb_h.status = CAM_REQ_ABORTED; + break; + } + rbuf[0] = (HPT_U8)(cap>>56); rbuf[1] = (HPT_U8)(cap>>48); rbuf[2] = (HPT_U8)(cap>>40);