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

Commit 3c05d92e authored by Herbert Xu's avatar Herbert Xu Committed by David S. Miller
Browse files

[TCP]: Compute in_sacked properly when we split up a TSO frame.



The problem is that the SACK fragmenting code may incorrectly call
tcp_fragment() with a length larger than the skb->len.  This happens
when the skb on the transmit queue completely falls to the LHS of the
SACK.

And add a BUG() check to tcp_fragment() so we can spot this kind of
error more quickly in the future.

Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 1619cca2
Loading
Loading
Loading
Loading
+9 −7
Original line number Original line Diff line number Diff line
@@ -979,14 +979,19 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_
			if (!before(TCP_SKB_CB(skb)->seq, end_seq))
			if (!before(TCP_SKB_CB(skb)->seq, end_seq))
				break;
				break;


			in_sack = !after(start_seq, TCP_SKB_CB(skb)->seq) &&
				!before(end_seq, TCP_SKB_CB(skb)->end_seq);

			pcount = tcp_skb_pcount(skb);
			pcount = tcp_skb_pcount(skb);


			if (pcount > 1 &&
			if (pcount > 1 && !in_sack &&
			    (after(start_seq, TCP_SKB_CB(skb)->seq) ||
			    after(TCP_SKB_CB(skb)->end_seq, start_seq)) {
			     before(end_seq, TCP_SKB_CB(skb)->end_seq))) {
				unsigned int pkt_len;
				unsigned int pkt_len;


				if (after(start_seq, TCP_SKB_CB(skb)->seq))
				in_sack = !after(start_seq,
						 TCP_SKB_CB(skb)->seq);

				if (!in_sack)
					pkt_len = (start_seq -
					pkt_len = (start_seq -
						   TCP_SKB_CB(skb)->seq);
						   TCP_SKB_CB(skb)->seq);
				else
				else
@@ -999,9 +1004,6 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb, u32 prior_snd_


			fack_count += pcount;
			fack_count += pcount;


			in_sack = !after(start_seq, TCP_SKB_CB(skb)->seq) &&
				!before(end_seq, TCP_SKB_CB(skb)->end_seq);

			sacked = TCP_SKB_CB(skb)->sacked;
			sacked = TCP_SKB_CB(skb)->sacked;


			/* Account D-SACK for retransmitted packet. */
			/* Account D-SACK for retransmitted packet. */
+2 −0
Original line number Original line Diff line number Diff line
@@ -435,6 +435,8 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len, unsigned int mss
	int nsize, old_factor;
	int nsize, old_factor;
	u16 flags;
	u16 flags;


	BUG_ON(len >= skb->len);

	nsize = skb_headlen(skb) - len;
	nsize = skb_headlen(skb) - len;
	if (nsize < 0)
	if (nsize < 0)
		nsize = 0;
		nsize = 0;