Commit 16fad69c authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller
Browse files

tcp: fix skb_availroom()

Chrome OS team reported a crash on a Pixel ChromeBook in TCP stack :

https://code.google.com/p/chromium/issues/detail?id=182056



commit a21d4572 (tcp: avoid order-1 allocations on wifi and tx
path) did a poor choice adding an 'avail_size' field to skb, while
what we really needed was a 'reserved_tailroom' one.

It would have avoided commit 22b4a4f2 (tcp: fix retransmit of
partially acked frames) and this commit.

Crash occurs because skb_split() is not aware of the 'avail_size'
management (and should not be aware)

Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
Reported-by: default avatarMukesh Agrawal <quiche@chromium.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent b701f16d
Loading
Loading
Loading
Loading
+5 −2
Original line number Original line Diff line number Diff line
@@ -500,7 +500,7 @@ struct sk_buff {
	union {
	union {
		__u32		mark;
		__u32		mark;
		__u32		dropcount;
		__u32		dropcount;
		__u32		avail_size;
		__u32		reserved_tailroom;
	};
	};


	sk_buff_data_t		inner_transport_header;
	sk_buff_data_t		inner_transport_header;
@@ -1447,7 +1447,10 @@ static inline int skb_tailroom(const struct sk_buff *skb)
 */
 */
static inline int skb_availroom(const struct sk_buff *skb)
static inline int skb_availroom(const struct sk_buff *skb)
{
{
	return skb_is_nonlinear(skb) ? 0 : skb->avail_size - skb->len;
	if (skb_is_nonlinear(skb))
		return 0;

	return skb->end - skb->tail - skb->reserved_tailroom;
}
}


/**
/**
+1 −1
Original line number Original line Diff line number Diff line
@@ -775,7 +775,7 @@ struct sk_buff *sk_stream_alloc_skb(struct sock *sk, int size, gfp_t gfp)
			 * Make sure that we have exactly size bytes
			 * Make sure that we have exactly size bytes
			 * available to the caller, no more, no less.
			 * available to the caller, no more, no less.
			 */
			 */
			skb->avail_size = size;
			skb->reserved_tailroom = skb->end - skb->tail - size;
			return skb;
			return skb;
		}
		}
		__kfree_skb(skb);
		__kfree_skb(skb);
+0 −1
Original line number Original line Diff line number Diff line
@@ -1298,7 +1298,6 @@ static void __pskb_trim_head(struct sk_buff *skb, int len)
	eat = min_t(int, len, skb_headlen(skb));
	eat = min_t(int, len, skb_headlen(skb));
	if (eat) {
	if (eat) {
		__skb_pull(skb, eat);
		__skb_pull(skb, eat);
		skb->avail_size -= eat;
		len -= eat;
		len -= eat;
		if (!len)
		if (!len)
			return;
			return;