diff options
author | Randall Stewart <rrs@FreeBSD.org> | 2021-06-11 15:38:08 +0000 |
---|---|---|
committer | Michael Tuexen <tuexen@FreeBSD.org> | 2021-06-14 21:00:17 +0000 |
commit | d0eaf95edcafcaeebfbc3ce9f361e98914830a49 (patch) | |
tree | 1a065d2420cdc637b7fe1a536ebbdbd7a9e8a7c7 /sys | |
parent | 8ecbecdcfdb082dc4056a9d627d5de2ed7eceda4 (diff) | |
download | src-d0eaf95edcafcaeebfbc3ce9f361e98914830a49.tar.gz src-d0eaf95edcafcaeebfbc3ce9f361e98914830a49.zip |
tcp: Missing mfree in rack and bbr
Recently (Nov) we added logic that protects against a peer negotiating a timestamp, and
then not including a timestamp. This involved in the input path doing a goto done_with_input
label. Now I suspect the code was cribbed from one in Rack that has to do with the SYN.
This had a bug, i.e. it should have a m_freem(m) before going to the label (bbr had this
missing m_freem() but rack did not). This then caused the missing m_freem to show
up in both BBR and Rack. Also looking at the code referencing m->m_pkthdr.lro_nsegs
later (after processing) is not a good idea, even though its only for logging. Best to
copy that off before any frees can take place.
Reviewed by: mtuexen
Sponsored by: Netflix Inc
Differential Revision: https://reviews.freebsd.org/D30727
(cherry picked from commit ba1b3e48f5be320f0590bc357ea53fdc3e4edc65)
Diffstat (limited to 'sys')
-rw-r--r-- | sys/netinet/tcp_stacks/bbr.c | 1 | ||||
-rw-r--r-- | sys/netinet/tcp_stacks/rack.c | 6 |
2 files changed, 6 insertions, 1 deletions
diff --git a/sys/netinet/tcp_stacks/bbr.c b/sys/netinet/tcp_stacks/bbr.c index 05db7180e7b2..06975c45cdbd 100644 --- a/sys/netinet/tcp_stacks/bbr.c +++ b/sys/netinet/tcp_stacks/bbr.c @@ -11441,6 +11441,7 @@ bbr_do_segment_nounlock(struct mbuf *m, struct tcphdr *th, struct socket *so, if ((tp->t_flags & TF_RCVD_TSTMP) && !(to.to_flags & TOF_TS) && ((thflags & TH_RST) == 0) && (V_tcp_tolerate_missing_ts == 0)) { retval = 0; + m_freem(m); goto done_with_input; } /* diff --git a/sys/netinet/tcp_stacks/rack.c b/sys/netinet/tcp_stacks/rack.c index f9ba67088f7a..dc3c8d47dc31 100644 --- a/sys/netinet/tcp_stacks/rack.c +++ b/sys/netinet/tcp_stacks/rack.c @@ -13452,6 +13452,7 @@ rack_do_segment_nounlock(struct mbuf *m, struct tcphdr *th, struct socket *so, #ifdef TCP_ACCOUNTING int ack_val_set = 0xf; #endif + int nsegs; uint32_t us_cts; /* * tv passed from common code is from either M_TSTMP_LRO or @@ -13463,6 +13464,7 @@ rack_do_segment_nounlock(struct mbuf *m, struct tcphdr *th, struct socket *so, if (m->m_flags & M_ACKCMP) { panic("Impossible reach m has ackcmp? m:%p tp:%p", m, tp); } + nsegs = m->m_pkthdr.lro_nsegs; counter_u64_add(rack_proc_non_comp_ack, 1); thflags = th->th_flags; #ifdef TCP_ACCOUNTING @@ -13605,6 +13607,7 @@ rack_do_segment_nounlock(struct mbuf *m, struct tcphdr *th, struct socket *so, if ((thflags & TH_SYN) && (thflags & TH_FIN) && V_drop_synfin) { way_out = 4; retval = 0; + m_freem(m); goto done_with_input; } /* @@ -13639,6 +13642,7 @@ rack_do_segment_nounlock(struct mbuf *m, struct tcphdr *th, struct socket *so, ((thflags & TH_RST) == 0) && (V_tcp_tolerate_missing_ts == 0)) { way_out = 5; retval = 0; + m_freem(m); goto done_with_input; } @@ -13942,7 +13946,7 @@ do_output_now: way_out = 2; } done_with_input: - rack_log_doseg_done(rack, cts, nxt_pkt, did_out, way_out, max(1, m->m_pkthdr.lro_nsegs)); + rack_log_doseg_done(rack, cts, nxt_pkt, did_out, way_out, max(1, nsegs)); if (did_out) rack->r_wanted_output = 0; #ifdef INVARIANTS |