DF-2468 / fix.diff
diff --git a/sys/dev/disk/iscsi/initiator/iscsi_subr.c b/sys/dev/disk/iscsi/initiator/iscsi_subr.c --- a/sys/dev/disk/iscsi/initiator/iscsi_subr.c +++ b/sys/dev/disk/iscsi/initiator/iscsi_subr.c @@ -151,13 +151,26 @@ bp = mtod(pq->mp, caddr_t); if((sense_len = scsi_2btoul(bp)) == 0) return 0; + /* + | The 2-byte sense_len is read directly off the (target-controlled) Data + | Segment and is NOT bounded by the actual Data Segment length the + | target sent (pp->ds_len). Without this clamp, a target that claims a + | large sense_len but sends a short Data Segment makes us kmalloc() a + | big scratch buffer that i_mbufcopy() only partially fills, leaving the + | rest as stale kernel heap which is then bcopy()'d into the CCB sense + | buffer (info leak), and can also read 2 bytes past the allocation. + */ + if(pp->ds_len < 2 || sense_len > pp->ds_len - 2) + sense_len = (pp->ds_len >= 2) ? pp->ds_len - 2 : 0; + if(sense_len == 0) + return 0; debug(4, "sense_len=%d", sense_len); /* | according to the specs, the sense data cannot | be larger than 252 ... */ if(sense_len > m->m_len) { - bp = kmalloc(sense_len, M_ISCSI, M_WAITOK); + bp = kmalloc(sense_len, M_ISCSI, M_WAITOK | M_ZERO); debug(3, "calling i_mbufcopy(len=%d)", sense_len); i_mbufcopy(pq->mp, bp, sense_len); mustfree++; |