aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Tuexen <tuexen@FreeBSD.org>2020-05-26 15:48:27 +0000
committerMichael Tuexen <tuexen@FreeBSD.org>2020-05-26 15:48:27 +0000
commit7e167c2e69d44b2f9decb99c3f3175f0f1db617e (patch)
tree8e727ad94e4e326d9a234d785a521c5153a35e79
parentae05ff00e3e3045bd7cff9b01b78eeb0c7a9c2b4 (diff)
downloadsrc-7e167c2e69d44b2f9decb99c3f3175f0f1db617e.tar.gz
src-7e167c2e69d44b2f9decb99c3f3175f0f1db617e.zip
MFS r361469: Fix bug in PR-SCTP
Only drop DATA chunk with lower priorities as specified in RFC 7496. This issue was found by looking at a reproducer generated by syzkaller. MFS r361472: Improve SCTP iterator Ensure that the SCTP iterator runs with an stcb and inp, which belong to each other. MFS r361473: Improve stcb handling during teardown Ensure that an stcb is not dereferenced when it is about to be freed. This issue was found by SYZKALLER. MFS r361476: Improve ASCONF handling Avoid an integer underflow. Approved by: re(gjb)
Notes
Notes: svn path=/releng/11.4/; revision=361522
-rw-r--r--sys/netinet/sctp_asconf.c6
-rw-r--r--sys/netinet/sctp_indata.c4
-rw-r--r--sys/netinet/sctp_indata.h3
-rw-r--r--sys/netinet/sctp_output.c8
-rw-r--r--sys/netinet/sctputil.c5
5 files changed, 19 insertions, 7 deletions
diff --git a/sys/netinet/sctp_asconf.c b/sys/netinet/sctp_asconf.c
index 5e9de075c8e2..d22461a1c1a2 100644
--- a/sys/netinet/sctp_asconf.c
+++ b/sys/netinet/sctp_asconf.c
@@ -1797,9 +1797,9 @@ sctp_handle_asconf_ack(struct mbuf *m, int offset,
} /* switch */
/* update remaining ASCONF-ACK message length to process */
- ack_length -= SCTP_SIZE32(param_length);
- if (ack_length <= 0) {
- /* no more data in the mbuf chain */
+ if (ack_length > SCTP_SIZE32(param_length)) {
+ ack_length -= SCTP_SIZE32(param_length);
+ } else {
break;
}
offset += SCTP_SIZE32(param_length);
diff --git a/sys/netinet/sctp_indata.c b/sys/netinet/sctp_indata.c
index 4216e5e4621c..c82d03200027 100644
--- a/sys/netinet/sctp_indata.c
+++ b/sys/netinet/sctp_indata.c
@@ -162,6 +162,9 @@ sctp_build_readq_entry(struct sctp_tcb *stcb,
read_queue_e->data = dm;
read_queue_e->stcb = stcb;
read_queue_e->port_from = stcb->rport;
+ if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) {
+ read_queue_e->do_not_ref_stcb = 1;
+ }
failed_build:
return (read_queue_e);
}
@@ -773,6 +776,7 @@ sctp_build_readq_entry_from_ctl(struct sctp_queued_to_read *nc, struct sctp_queu
atomic_add_int(&nc->whoFrom->ref_count, 1);
nc->stcb = control->stcb;
nc->port_from = control->port_from;
+ nc->do_not_ref_stcb = control->do_not_ref_stcb;
}
static void
diff --git a/sys/netinet/sctp_indata.h b/sys/netinet/sctp_indata.h
index 4dce1890e7fa..63712300c1ed 100644
--- a/sys/netinet/sctp_indata.h
+++ b/sys/netinet/sctp_indata.h
@@ -66,6 +66,9 @@ sctp_build_readq_entry(struct sctp_tcb *stcb,
(_ctl)->data = dm; \
(_ctl)->stcb = (in_it); \
(_ctl)->port_from = (in_it)->rport; \
+ if ((in_it)->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { \
+ (_ctl)->do_not_ref_stcb = 1; \
+ }\
} \
} while (0)
diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c
index bf6adcc46cc9..e91141c90193 100644
--- a/sys/netinet/sctp_output.c
+++ b/sys/netinet/sctp_output.c
@@ -6198,11 +6198,11 @@ sctp_prune_prsctp(struct sctp_tcb *stcb,
* This one is PR-SCTP AND buffer space
* limited type
*/
- if (chk->rec.data.timetodrop.tv_sec >= (long)srcv->sinfo_timetolive) {
+ if (chk->rec.data.timetodrop.tv_sec > (long)srcv->sinfo_timetolive) {
/*
* Lower numbers equates to higher
* priority so if the one we are
- * looking at has a larger or equal
+ * looking at has a larger
* priority we want to drop the data
* and NOT retransmit it.
*/
@@ -6233,7 +6233,7 @@ sctp_prune_prsctp(struct sctp_tcb *stcb,
TAILQ_FOREACH_SAFE(chk, &asoc->send_queue, sctp_next, nchk) {
/* Here we must move to the sent queue and mark */
if (PR_SCTP_BUF_ENABLED(chk->flags)) {
- if (chk->rec.data.timetodrop.tv_sec >= (long)srcv->sinfo_timetolive) {
+ if (chk->rec.data.timetodrop.tv_sec > (long)srcv->sinfo_timetolive) {
if (chk->data) {
/*
* We release the book_size
@@ -12614,7 +12614,7 @@ sctp_lower_sosend(struct socket *so,
top = SCTP_HEADER_TO_CHAIN(i_pak);
sndlen = SCTP_HEADER_LEN(i_pak);
}
- SCTPDBG(SCTP_DEBUG_OUTPUT1, "Send called addr:%p send length %zu\n",
+ SCTPDBG(SCTP_DEBUG_OUTPUT1, "Send called addr:%p send length %zd\n",
(void *)addr,
sndlen);
if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) &&
diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c
index b91a6c8041ca..de84d3bbe3c6 100644
--- a/sys/netinet/sctputil.c
+++ b/sys/netinet/sctputil.c
@@ -1409,6 +1409,7 @@ select_a_new_ep:
}
tinp = it->inp;
it->inp = LIST_NEXT(it->inp, sctp_list);
+ it->stcb = NULL;
SCTP_INP_RUNLOCK(tinp);
if (it->inp == NULL) {
goto done_with_iterator;
@@ -1478,6 +1479,9 @@ select_a_new_ep:
atomic_add_int(&it->stcb->asoc.refcnt, -1);
iteration_count = 0;
}
+ KASSERT(it->inp == it->stcb->sctp_ep,
+ ("%s: stcb %p does not belong to inp %p, but inp %p",
+ __func__, it->stcb, it->inp, it->stcb->sctp_ep));
/* run function on this one */
(*it->function_assoc) (it->inp, it->stcb, it->pointer, it->val);
@@ -1510,6 +1514,7 @@ no_stcb:
} else {
it->inp = LIST_NEXT(it->inp, sctp_list);
}
+ it->stcb = NULL;
if (it->inp == NULL) {
goto done_with_iterator;
}