Skip to content

Commit 9150b10

Browse files
Eric Dumazetgregkh
Eric Dumazet
authored andcommitted
tcp: do not underestimate skb->truesize in tcp_trim_head()
[ Upstream commit 7162fb2 ] Andrey found a way to trigger the WARN_ON_ONCE(delta < len) in skb_try_coalesce() using syzkaller and a filter attached to a TCP socket over loopback interface. I believe one issue with looped skbs is that tcp_trim_head() can end up producing skb with under estimated truesize. It hardly matters for normal conditions, since packets sent over loopback are never truncated. Bytes trimmed from skb->head should not change skb truesize, since skb->head is not reallocated. Signed-off-by: Eric Dumazet <[email protected]> Reported-by: Andrey Konovalov <[email protected]> Tested-by: Andrey Konovalov <[email protected]> Signed-off-by: David S. Miller <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 097994b commit 9150b10

File tree

1 file changed

+12
-7
lines changed

1 file changed

+12
-7
lines changed

net/ipv4/tcp_output.c

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1221,7 +1221,7 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len,
12211221
* eventually). The difference is that pulled data not copied, but
12221222
* immediately discarded.
12231223
*/
1224-
static void __pskb_trim_head(struct sk_buff *skb, int len)
1224+
static int __pskb_trim_head(struct sk_buff *skb, int len)
12251225
{
12261226
struct skb_shared_info *shinfo;
12271227
int i, k, eat;
@@ -1231,7 +1231,7 @@ static void __pskb_trim_head(struct sk_buff *skb, int len)
12311231
__skb_pull(skb, eat);
12321232
len -= eat;
12331233
if (!len)
1234-
return;
1234+
return 0;
12351235
}
12361236
eat = len;
12371237
k = 0;
@@ -1257,23 +1257,28 @@ static void __pskb_trim_head(struct sk_buff *skb, int len)
12571257
skb_reset_tail_pointer(skb);
12581258
skb->data_len -= len;
12591259
skb->len = skb->data_len;
1260+
return len;
12601261
}
12611262

12621263
/* Remove acked data from a packet in the transmit queue. */
12631264
int tcp_trim_head(struct sock *sk, struct sk_buff *skb, u32 len)
12641265
{
1266+
u32 delta_truesize;
1267+
12651268
if (skb_unclone(skb, GFP_ATOMIC))
12661269
return -ENOMEM;
12671270

1268-
__pskb_trim_head(skb, len);
1271+
delta_truesize = __pskb_trim_head(skb, len);
12691272

12701273
TCP_SKB_CB(skb)->seq += len;
12711274
skb->ip_summed = CHECKSUM_PARTIAL;
12721275

1273-
skb->truesize -= len;
1274-
sk->sk_wmem_queued -= len;
1275-
sk_mem_uncharge(sk, len);
1276-
sock_set_flag(sk, SOCK_QUEUE_SHRUNK);
1276+
if (delta_truesize) {
1277+
skb->truesize -= delta_truesize;
1278+
sk->sk_wmem_queued -= delta_truesize;
1279+
sk_mem_uncharge(sk, delta_truesize);
1280+
sock_set_flag(sk, SOCK_QUEUE_SHRUNK);
1281+
}
12771282

12781283
/* Any change of skb->len requires recalculation of tso factor. */
12791284
if (tcp_skb_pcount(skb) > 1)

0 commit comments

Comments
 (0)