Fix cases where the TFO pending counter would leak references, and eventually, memory.

Also renamed some tfo labels and added/reworked comments for clarity.

Based on an initial patch from jtl.

PR: 213424
Reviewed by:	jtl
MFC after:	1 week
Differential Revision:	https://reviews.freebsd.org/D8235
This commit is contained in:
Patrick Kelsey 2016-10-15 01:41:28 +00:00
parent 82676a28eb
commit 09c305eb65
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=307337
2 changed files with 26 additions and 12 deletions

View File

@ -1121,7 +1121,7 @@ tcp_input(struct mbuf **mp, int *offp, int proto)
goto dropwithreset;
}
#ifdef TCP_RFC7413
new_tfo_socket:
tfo_socket_result:
#endif
if (so == NULL) {
/*
@ -1387,7 +1387,7 @@ tcp_input(struct mbuf **mp, int *offp, int proto)
tcp_dooptions(&to, optp, optlen, TO_SYN);
#ifdef TCP_RFC7413
if (syncache_add(&inc, &to, th, inp, &so, m, NULL, NULL))
goto new_tfo_socket;
goto tfo_socket_result;
#else
syncache_add(&inc, &to, th, inp, &so, m, NULL, NULL);
#endif

View File

@ -1151,11 +1151,10 @@ syncache_tfo_expand(struct syncache *sc, struct socket **lsop, struct mbuf *m,
* the data, we avoid this DoS scenario.
*
* The exception to the above is when a SYN with a valid TCP Fast Open (TFO)
* cookie is processed, V_tcp_fastopen_enabled set to true, and the
* TCP_FASTOPEN socket option is set. In this case, a new socket is created
* and returned via lsop, the mbuf is not freed so that tcp_input() can
* queue its data to the socket, and 1 is returned to indicate the
* TFO-socket-creation path was taken.
* cookie is processed and a new socket is created. In this case, any data
* accompanying the SYN will be queued to the socket by tcp_input() and will
* be ACKed either when the application sends response data or the delayed
* ACK timer expires, whichever comes first.
*/
int
syncache_add(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th,
@ -1181,6 +1180,7 @@ syncache_add(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th,
struct ucred *cred;
#ifdef TCP_RFC7413
uint64_t tfo_response_cookie;
unsigned int *tfo_pending = NULL;
int tfo_cookie_valid = 0;
int tfo_response_cookie_valid = 0;
#endif
@ -1226,8 +1226,13 @@ syncache_add(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th,
&tfo_response_cookie);
tfo_cookie_valid = (result > 0);
tfo_response_cookie_valid = (result >= 0);
} else
atomic_subtract_int(tp->t_tfo_pending, 1);
}
/*
* Remember the TFO pending counter as it will have to be
* decremented below if we don't make it to syncache_tfo_expand().
*/
tfo_pending = tp->t_tfo_pending;
}
#endif
@ -1468,9 +1473,9 @@ syncache_add(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th,
#ifdef TCP_RFC7413
if (tfo_cookie_valid) {
syncache_tfo_expand(sc, lsop, m, tfo_response_cookie);
/* INP_WUNLOCK(inp) will be performed by the called */
/* INP_WUNLOCK(inp) will be performed by the caller */
rv = 1;
goto tfo_done;
goto tfo_expanded;
}
#endif
@ -1496,7 +1501,16 @@ syncache_add(struct in_conninfo *inc, struct tcpopt *to, struct tcphdr *th,
m_freem(m);
}
#ifdef TCP_RFC7413
tfo_done:
/*
* If tfo_pending is not NULL here, then a TFO SYN that did not
* result in a new socket was processed and the associated pending
* counter has not yet been decremented. All such TFO processing paths
* transit this point.
*/
if (tfo_pending != NULL)
tcp_fastopen_decrement_counter(tfo_pending);
tfo_expanded:
#endif
if (cred != NULL)
crfree(cred);