summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorrrs <rrs@FreeBSD.org>2007-06-15 17:59:57 +0000
committerrrs <rrs@FreeBSD.org>2007-06-15 17:59:57 +0000
commit57b3f6ebdecb9baca61db7b79bd89926b5be6c2e (patch)
treea0242057ec0c3b373ca3da10937b024b87996162 /sys
parent6b110dc4737f233a6f6e37b1f2fafa7bdeee7520 (diff)
downloadFreeBSD-src-57b3f6ebdecb9baca61db7b79bd89926b5be6c2e.zip
FreeBSD-src-57b3f6ebdecb9baca61db7b79bd89926b5be6c2e.tar.gz
- Issue one, new stack reduction left packet_drop handling still
thinking it had the whole chunk. This could cause a crash if a large packet drop came in. Fixed by adjusting the trunc length down to the limit. - Large sacks with lots of segments could also have same issue. Changed duplicate and segment handling to use proper get_m_ptr function to pull each block from mbuf chains.
Diffstat (limited to 'sys')
-rw-r--r--sys/netinet/sctp_indata.c47
-rw-r--r--sys/netinet/sctp_indata.h2
-rw-r--r--sys/netinet/sctp_input.c19
3 files changed, 44 insertions, 24 deletions
diff --git a/sys/netinet/sctp_indata.c b/sys/netinet/sctp_indata.c
index 49fd598..fd5661b 100644
--- a/sys/netinet/sctp_indata.c
+++ b/sys/netinet/sctp_indata.c
@@ -2764,7 +2764,7 @@ sctp_process_data(struct mbuf **mm, int iphlen, int *offset, int length,
}
static void
-sctp_handle_segments(struct sctp_tcb *stcb, struct sctp_association *asoc,
+sctp_handle_segments(struct mbuf *m, int *offset, struct sctp_tcb *stcb, struct sctp_association *asoc,
struct sctp_sack_chunk *ch, uint32_t last_tsn, uint32_t * biggest_tsn_acked,
uint32_t * biggest_newly_acked_tsn, uint32_t * this_sack_lowest_newack,
int num_seg, int *ecn_seg_sums)
@@ -2773,7 +2773,7 @@ sctp_handle_segments(struct sctp_tcb *stcb, struct sctp_association *asoc,
/* process fragments and update sendqueue */
/************************************************/
struct sctp_sack *sack;
- struct sctp_gap_ack_block *frag;
+ struct sctp_gap_ack_block *frag, block;
struct sctp_tmit_chunk *tp1;
int i;
unsigned int j;
@@ -2790,10 +2790,14 @@ sctp_handle_segments(struct sctp_tcb *stcb, struct sctp_association *asoc,
} else {
primary_flag_set = 0;
}
-
sack = &ch->sack;
- frag = (struct sctp_gap_ack_block *)((caddr_t)sack +
- sizeof(struct sctp_sack));
+
+ frag = (struct sctp_gap_ack_block *)sctp_m_getptr(m, *offset,
+ sizeof(struct sctp_gap_ack_block), (uint8_t *) & block);
+ *offset += sizeof(block);
+ if (frag == NULL) {
+ return;
+ }
tp1 = NULL;
last_frag_high = 0;
for (i = 0; i < num_seg; i++) {
@@ -3042,7 +3046,12 @@ sctp_handle_segments(struct sctp_tcb *stcb, struct sctp_association *asoc,
tp1 = TAILQ_NEXT(tp1, sctp_next);
} /* end while (tp1) */
} /* end for (j = fragStart */
- frag++; /* next one */
+ frag = (struct sctp_gap_ack_block *)sctp_m_getptr(m, *offset,
+ sizeof(struct sctp_gap_ack_block), (uint8_t *) & block);
+ *offset += sizeof(block);
+ if (frag == NULL) {
+ break;
+ }
}
if (sctp_logging_level & SCTP_FR_LOGGING_ENABLE) {
if (num_frs)
@@ -4578,7 +4587,8 @@ again:
void
-sctp_handle_sack(struct sctp_sack_chunk *ch, struct sctp_tcb *stcb,
+sctp_handle_sack(struct mbuf *m, int offset,
+ struct sctp_sack_chunk *ch, struct sctp_tcb *stcb,
struct sctp_nets *net_from, int *abort_now, int sack_len, uint32_t rwnd)
{
struct sctp_association *asoc;
@@ -4658,15 +4668,24 @@ sctp_handle_sack(struct sctp_sack_chunk *ch, struct sctp_tcb *stcb,
}
if ((num_dup) && (sctp_logging_level & (SCTP_FR_LOGGING_ENABLE | SCTP_EARLYFR_LOGGING_ENABLE))) {
int off_to_dup, iii;
- uint32_t *dupdata;
+ uint32_t *dupdata, dblock;
off_to_dup = (num_seg * sizeof(struct sctp_gap_ack_block)) + sizeof(struct sctp_sack_chunk);
if ((off_to_dup + (num_dup * sizeof(uint32_t))) <= sack_length) {
- dupdata = (uint32_t *) ((caddr_t)ch + off_to_dup);
- for (iii = 0; iii < num_dup; iii++) {
- sctp_log_fr(*dupdata, 0, 0, SCTP_FR_DUPED);
- dupdata++;
+ dupdata = (uint32_t *) sctp_m_getptr(m, off_to_dup,
+ sizeof(uint32_t), (uint8_t *) & dblock);
+ off_to_dup += sizeof(uint32_t);
+ if (dupdata) {
+ for (iii = 0; iii < num_dup; iii++) {
+ sctp_log_fr(*dupdata, 0, 0, SCTP_FR_DUPED);
+ dupdata = (uint32_t *) sctp_m_getptr(m, off_to_dup,
+ sizeof(uint32_t), (uint8_t *) & dblock);
+ if (dupdata == NULL)
+ break;
+ off_to_dup += sizeof(uint32_t);
+
+ }
}
} else {
SCTP_PRINTF("Size invalid offset to dups:%d number dups:%d sack_len:%d num gaps:%d\n",
@@ -4904,6 +4923,8 @@ sctp_handle_sack(struct sctp_sack_chunk *ch, struct sctp_tcb *stcb,
/* always set this up to cum-ack */
asoc->this_sack_highest_gap = last_tsn;
+ /* Move offset up to point to gaps/dups */
+ offset += sizeof(struct sctp_sack_chunk);
if (((num_seg * (sizeof(struct sctp_gap_ack_block))) + sizeof(struct sctp_sack_chunk)) > sack_length) {
/* skip corrupt segments */
@@ -4927,7 +4948,7 @@ sctp_handle_sack(struct sctp_sack_chunk *ch, struct sctp_tcb *stcb,
* handling NEWLY ACKED chunks. this_sack_lowest_newack is
* used for CMT DAC algo. saw_newack will also change.
*/
- sctp_handle_segments(stcb, asoc, ch, last_tsn,
+ sctp_handle_segments(m, &offset, stcb, asoc, ch, last_tsn,
&biggest_tsn_acked, &biggest_tsn_newly_acked, &this_sack_lowest_newack,
num_seg, &ecn_seg_sums);
diff --git a/sys/netinet/sctp_indata.h b/sys/netinet/sctp_indata.h
index 3ec0273..8a65a20 100644
--- a/sys/netinet/sctp_indata.h
+++ b/sys/netinet/sctp_indata.h
@@ -96,7 +96,7 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
uint32_t rwnd, int nonce_sum_flag, int *abort_now);
void
-sctp_handle_sack(struct sctp_sack_chunk *, struct sctp_tcb *,
+sctp_handle_sack(struct mbuf *m, int offset, struct sctp_sack_chunk *, struct sctp_tcb *,
struct sctp_nets *, int *, int, uint32_t);
/* draft-ietf-tsvwg-usctp */
diff --git a/sys/netinet/sctp_input.c b/sys/netinet/sctp_input.c
index 0baeaba..2578d9f 100644
--- a/sys/netinet/sctp_input.c
+++ b/sys/netinet/sctp_input.c
@@ -3177,7 +3177,7 @@ strres_nochunk:
*/
static void
sctp_handle_packet_dropped(struct sctp_pktdrop_chunk *cp,
- struct sctp_tcb *stcb, struct sctp_nets *net)
+ struct sctp_tcb *stcb, struct sctp_nets *net, uint32_t limit)
{
uint32_t bottle_bw, on_queue;
uint16_t trunc_len;
@@ -3200,6 +3200,9 @@ sctp_handle_packet_dropped(struct sctp_pktdrop_chunk *cp,
memset(&desc, 0, sizeof(desc));
}
trunc_len = (uint16_t) ntohs(cp->trunc_len);
+ if (trunc_len > limit) {
+ trunc_len = limit;
+ }
/* now the chunks themselves */
while ((ch != NULL) && (chlen >= sizeof(struct sctp_chunkhdr))) {
desc.chunk_type = ch->chunk_type;
@@ -3889,7 +3892,8 @@ process_control_chunks:
&abort_now);
} else {
if (netp && *netp)
- sctp_handle_sack(sack, stcb, *netp, &abort_now, chk_length, a_rwnd);
+ sctp_handle_sack(m, *offset,
+ sack, stcb, *netp, &abort_now, chk_length, a_rwnd);
}
if (abort_now) {
/* ABORT signal from sack processing */
@@ -4233,8 +4237,6 @@ process_control_chunks:
break;
case SCTP_STREAM_RESET:
SCTPDBG(SCTP_DEBUG_INPUT3, "SCTP_STREAM_RESET\n");
- ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, *offset,
- chk_length, chunk_buf);
if (((stcb == NULL) || (ch == NULL) || (chk_length < sizeof(struct sctp_stream_reset_tsn_req)))) {
/* Its not ours */
if (locked_tcb) {
@@ -4274,12 +4276,11 @@ process_control_chunks:
*offset = length;
return (NULL);
}
- ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, *offset,
- chk_length, chunk_buf);
-
if (ch && (stcb) && netp && (*netp)) {
sctp_handle_packet_dropped((struct sctp_pktdrop_chunk *)ch,
- stcb, *netp);
+ stcb, *netp,
+ min(chk_length, (sizeof(chunk_buf) - 4)));
+
}
break;
@@ -4312,8 +4313,6 @@ process_control_chunks:
/* skip this chunk... it's already auth'd */
goto next_chunk;
}
- ch = (struct sctp_chunkhdr *)sctp_m_getptr(m, *offset,
- chk_length, chunk_buf);
got_auth = 1;
if ((ch == NULL) || sctp_handle_auth(stcb, (struct sctp_auth_chunk *)ch,
m, *offset)) {
OpenPOWER on IntegriCloud