Commit 158f323b authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller

net: adjust skb->truesize in pskb_expand_head()

Slava Shwartsman reported a warning in skb_try_coalesce(), when we
detect skb->truesize is completely wrong.

In his case, issue came from IPv6 reassembly coping with malicious
datagrams, that forced various pskb_may_pull() to reallocate a bigger
skb->head than the one allocated by NIC driver before entering GRO
layer.

Current code does not change skb->truesize, leaving this burden to
callers if they care enough.

Blindly changing skb->truesize in pskb_expand_head() is not
easy, as some producers might track skb->truesize, for example
in xmit path for back pressure feedback (sk->sk_wmem_alloc)

We can detect the cases where it should be safe to change
skb->truesize :

1) skb is not attached to a socket.
2) If it is attached to a socket, destructor is sock_edemux()

My audit gave only two callers doing their own skb->truesize
manipulation.

I had to remove skb parameter in sock_edemux macro when
CONFIG_INET is not set to avoid a compile error.
Signed-off-by: default avatarEric Dumazet <edumazet@google.com>
Reported-by: default avatarSlava Shwartsman <slavash@mellanox.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent b41fd8fd
...@@ -1534,7 +1534,7 @@ void sock_efree(struct sk_buff *skb); ...@@ -1534,7 +1534,7 @@ void sock_efree(struct sk_buff *skb);
#ifdef CONFIG_INET #ifdef CONFIG_INET
void sock_edemux(struct sk_buff *skb); void sock_edemux(struct sk_buff *skb);
#else #else
#define sock_edemux(skb) sock_efree(skb) #define sock_edemux sock_efree
#endif #endif
int sock_setsockopt(struct socket *sock, int level, int op, int sock_setsockopt(struct socket *sock, int level, int op,
......
...@@ -1192,10 +1192,10 @@ EXPORT_SYMBOL(__pskb_copy_fclone); ...@@ -1192,10 +1192,10 @@ EXPORT_SYMBOL(__pskb_copy_fclone);
int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail, int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
gfp_t gfp_mask) gfp_t gfp_mask)
{ {
int i; int i, osize = skb_end_offset(skb);
u8 *data; int size = osize + nhead + ntail;
int size = nhead + skb_end_offset(skb) + ntail;
long off; long off;
u8 *data;
BUG_ON(nhead < 0); BUG_ON(nhead < 0);
...@@ -1257,6 +1257,14 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail, ...@@ -1257,6 +1257,14 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
skb->hdr_len = 0; skb->hdr_len = 0;
skb->nohdr = 0; skb->nohdr = 0;
atomic_set(&skb_shinfo(skb)->dataref, 1); atomic_set(&skb_shinfo(skb)->dataref, 1);
/* It is not generally safe to change skb->truesize.
* For the moment, we really care of rx path, or
* when skb is orphaned (not attached to a socket).
*/
if (!skb->sk || skb->destructor == sock_edemux)
skb->truesize += size - osize;
return 0; return 0;
nofrags: nofrags:
......
...@@ -1210,11 +1210,9 @@ static struct sk_buff *netlink_trim(struct sk_buff *skb, gfp_t allocation) ...@@ -1210,11 +1210,9 @@ static struct sk_buff *netlink_trim(struct sk_buff *skb, gfp_t allocation)
skb = nskb; skb = nskb;
} }
if (!pskb_expand_head(skb, 0, -delta, pskb_expand_head(skb, 0, -delta,
(allocation & ~__GFP_DIRECT_RECLAIM) | (allocation & ~__GFP_DIRECT_RECLAIM) |
__GFP_NOWARN | __GFP_NORETRY)) __GFP_NOWARN | __GFP_NORETRY);
skb->truesize -= delta;
return skb; return skb;
} }
......
...@@ -618,8 +618,6 @@ int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr, ...@@ -618,8 +618,6 @@ int ieee80211_data_from_8023(struct sk_buff *skb, const u8 *addr,
if (pskb_expand_head(skb, head_need, 0, GFP_ATOMIC)) if (pskb_expand_head(skb, head_need, 0, GFP_ATOMIC))
return -ENOMEM; return -ENOMEM;
skb->truesize += head_need;
} }
if (encaps_data) { if (encaps_data) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment