Fix SCTP stream reset vulnerability.
We would like to acknowledge Gerasimos Dimitriadis who reported the issue and Michael Tuexen who analyzed and provided the fix. Security: FreeBSD-SA-15:03.sctp Security: CVE-2014-8613 Submitted by: tuexen
This commit is contained in:
parent
38f2a43815
commit
6a58f0e913
@ -3649,6 +3649,9 @@ sctp_handle_stream_reset_response(struct sctp_tcb *stcb,
|
||||
/* 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 @@ __attribute__((noinline))
|
||||
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)
|
||||
break;
|
||||
param_len = ntohs(ph->param_length);
|
||||
if (param_len < (int)sizeof(struct sctp_stream_reset_tsn_request)) {
|
||||
/* bad param */
|
||||
if (ph == NULL) {
|
||||
/* TSNH */
|
||||
break;
|
||||
}
|
||||
ph = (struct sctp_paramhdr *)sctp_m_getptr(m, offset, min(param_len, (int)sizeof(cstore)),
|
||||
param_len = ntohs(ph->param_length);
|
||||
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, 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 @@ __attribute__((noinline))
|
||||
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,12 +4139,18 @@ __attribute__((noinline))
|
||||
} 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);
|
||||
} 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 @@ __attribute__((noinline))
|
||||
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 @@ __attribute__((noinline))
|
||||
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 */
|
||||
|
Loading…
Reference in New Issue
Block a user