mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-04 04:04:19 +00:00
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: Eric Dumazet <edumazet@google.com> Reported-by: Slava Shwartsman <slavash@mellanox.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
b41fd8fdef
commit
158f323b98
@ -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);
|
|||||||
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,
|
|||||||
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)
|
|||||||
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,
|
|||||||
|
|
||||||
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) {
|
||||||
|
Loading…
Reference in New Issue
Block a user