Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 21684dc4 authored by Stefan Baranoff's avatar Stefan Baranoff Committed by David S. Miller
Browse files

tcp: fix sequence numbers for repaired sockets re-using TIME-WAIT sockets



This patch fixes a bug where the sequence numbers of a socket created using
TCP repair functionality are lower than set after connect is called.
This occurs when the repair socket overlaps with a TIME-WAIT socket and
triggers the re-use code. The amount lower is equal to the number of times
that a particular IP/port set is re-used and then put back into TIME-WAIT.
Re-using the first time the sequence number is 1 lower, closing that socket
and then re-opening (with repair) a new socket with the same addresses/ports
puts the sequence number 2 lower than set via setsockopt. The third time is
3 lower, etc. I have not tested what the limit of this acrewal is, if any.

The fix is, if a socket is in repair mode, to respect the already set
sequence number and timestamp when it would have already re-used the
TIME-WAIT socket.

Signed-off-by: default avatarStefan Baranoff <sbaranoff@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 83fe6b87
Loading
Loading
Loading
Loading
+18 −5
Original line number Diff line number Diff line
@@ -156,11 +156,24 @@ int tcp_twsk_unique(struct sock *sk, struct sock *sktw, void *twp)
	 */
	if (tcptw->tw_ts_recent_stamp &&
	    (!twp || (reuse && get_seconds() - tcptw->tw_ts_recent_stamp > 1))) {
		/* In case of repair and re-using TIME-WAIT sockets we still
		 * want to be sure that it is safe as above but honor the
		 * sequence numbers and time stamps set as part of the repair
		 * process.
		 *
		 * Without this check re-using a TIME-WAIT socket with TCP
		 * repair would accumulate a -1 on the repair assigned
		 * sequence number. The first time it is reused the sequence
		 * is -1, the second time -2, etc. This fixes that issue
		 * without appearing to create any others.
		 */
		if (likely(!tp->repair)) {
			tp->write_seq = tcptw->tw_snd_nxt + 65535 + 2;
			if (tp->write_seq == 0)
				tp->write_seq = 1;
			tp->rx_opt.ts_recent	   = tcptw->tw_ts_recent;
			tp->rx_opt.ts_recent_stamp = tcptw->tw_ts_recent_stamp;
		}
		sock_hold(sktw);
		return 1;
	}