Index: sys/netinet/sctp_input.c =================================================================== --- sys/netinet/sctp_input.c (revision 277788) +++ sys/netinet/sctp_input.c (working copy) @@ -3649,6 +3649,9 @@ sctp_handle_stream_reset_response(struct sctp_tcb /* huh ? */ return (0); } + if (ntohs(respin->ph.param_length) < sizeof(struct sctp_stream_reset_response_tsn)) { + return (0); + } if (action == SCTP_STREAM_RESET_RESULT_PERFORMED) { resp = (struct sctp_stream_reset_response_tsn *)respin; asoc->stream_reset_outstanding--; @@ -4037,7 +4040,7 @@ __attribute__((noinline)) sctp_handle_stream_reset(struct sctp_tcb *stcb, struct mbuf *m, int offset, struct sctp_chunkhdr *ch_req) { - int chk_length, param_len, ptype; + uint16_t remaining_length, param_len, ptype; struct sctp_paramhdr pstore; uint8_t cstore[SCTP_CHUNK_BUFFER_SIZE]; uint32_t seq = 0; @@ -4050,7 +4053,7 @@ __attribute__((noinline)) int num_param = 0; /* now it may be a reset or a reset-response */ - chk_length = ntohs(ch_req->chunk_length); + remaining_length = ntohs(ch_req->chunk_length) - sizeof(struct sctp_chunkhdr); /* setup for adding the response */ sctp_alloc_a_chunk(stcb, chk); @@ -4088,20 +4091,27 @@ strres_nochunk: ch->chunk_length = htons(chk->send_size); SCTP_BUF_LEN(chk->data) = SCTP_SIZE32(chk->send_size); offset += sizeof(struct sctp_chunkhdr); - while ((size_t)chk_length >= sizeof(struct sctp_stream_reset_tsn_request)) { + while (remaining_length >= sizeof(struct sctp_paramhdr)) { ph = (struct sctp_paramhdr *)sctp_m_getptr(m, offset, sizeof(pstore), (uint8_t *) & pstore); - if (ph == NULL) + if (ph == NULL) { + /* TSNH */ break; + } param_len = ntohs(ph->param_length); - if (param_len < (int)sizeof(struct sctp_stream_reset_tsn_request)) { - /* bad param */ + if ((param_len > remaining_length) || + (param_len < (sizeof(struct sctp_paramhdr) + sizeof(uint32_t)))) { + /* bad parameter length */ break; } - ph = (struct sctp_paramhdr *)sctp_m_getptr(m, offset, min(param_len, (int)sizeof(cstore)), + ph = (struct sctp_paramhdr *)sctp_m_getptr(m, offset, min(param_len, sizeof(cstore)), (uint8_t *) & cstore); + if (ph == NULL) { + /* TSNH */ + break; + } ptype = ntohs(ph->param_type); num_param++; - if (param_len > (int)sizeof(cstore)) { + if (param_len > sizeof(cstore)) { trunc = 1; } else { trunc = 0; @@ -4113,6 +4123,9 @@ strres_nochunk: if (ptype == SCTP_STR_RESET_OUT_REQUEST) { struct sctp_stream_reset_out_request *req_out; + if (param_len < sizeof(struct sctp_stream_reset_out_request)) { + break; + } req_out = (struct sctp_stream_reset_out_request *)ph; num_req++; if (stcb->asoc.stream_reset_outstanding) { @@ -4126,6 +4139,9 @@ strres_nochunk: } else if (ptype == SCTP_STR_RESET_ADD_OUT_STREAMS) { struct sctp_stream_reset_add_strm *str_add; + if (param_len < sizeof(struct sctp_stream_reset_add_strm)) { + break; + } str_add = (struct sctp_stream_reset_add_strm *)ph; num_req++; sctp_handle_str_reset_add_strm(stcb, chk, str_add); @@ -4132,6 +4148,9 @@ strres_nochunk: } else if (ptype == SCTP_STR_RESET_ADD_IN_STREAMS) { struct sctp_stream_reset_add_strm *str_add; + if (param_len < sizeof(struct sctp_stream_reset_add_strm)) { + break; + } str_add = (struct sctp_stream_reset_add_strm *)ph; num_req++; sctp_handle_str_reset_add_out_strm(stcb, chk, str_add); @@ -4156,6 +4175,9 @@ strres_nochunk: struct sctp_stream_reset_response *resp; uint32_t result; + if (param_len < sizeof(struct sctp_stream_reset_response)) { + break; + } resp = (struct sctp_stream_reset_response *)ph; seq = ntohl(resp->response_seq); result = ntohl(resp->result); @@ -4167,7 +4189,11 @@ strres_nochunk: break; } offset += SCTP_SIZE32(param_len); - chk_length -= SCTP_SIZE32(param_len); + if (remaining_length >= SCTP_SIZE32(param_len)) { + remaining_length -= SCTP_SIZE32(param_len); + } else { + remaining_length = 0; + } } if (num_req == 0) { /* we have no response free the stuff */