- 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.
This commit is contained in:
Randall Stewart 2007-06-15 17:59:57 +00:00
parent 02a50a14b3
commit 458303da65
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=170781
3 changed files with 44 additions and 24 deletions

View File

@ -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 @@ sctp_express_handle_sack(struct sctp_tcb *stcb, uint32_t cumack,
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);

View File

@ -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 */

View File

@ -3177,7 +3177,7 @@ sctp_handle_stream_reset(struct sctp_tcb *stcb, struct sctp_stream_reset_out_req
*/
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 @@ __attribute__((noinline))
&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 @@ __attribute__((noinline))
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 @@ __attribute__((noinline))
*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 @@ __attribute__((noinline))
/* 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)) {