[RHEL7,COMMIT] ms/net: adjust skb->truesize in pskb_expand_head()

Submitted by Konstantin Khorenko on April 20, 2020, 5:56 p.m.

Details

Message ID 202004201756.03KHuwM9028910@finist-ce7.sw.ru
State New
Series "ms/net: adjust skb->truesize in pskb_expand_head()"
Headers show

Commit Message

Konstantin Khorenko April 20, 2020, 5:56 p.m.
The commit is pushed to "branch-rh7-3.10.0-1127.vz7.150.x-ovz" and will appear at https://src.openvz.org/scm/ovz/vzkernel.git
after rh7-3.10.0-1127.vz7.150.2
------>
commit 13a3a2eb26a97afaea34b3a4165b5ff663d5173e
Author: Eric Dumazet <edumazet@google.com>
Date:   Fri Jan 27 07:11:27 2017 -0800

    ms/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>
    
    https://jira.sw.ru/browse/PSBM-102386
    https://github.com/tempesta-tech/tempesta/issues/926
    
    (cherry picked from commit 158f323b9868b59967ad96957c4ca388161be321)
    Signed-off-by: Konstantin Khorenko <khorenko@virtuozzo.com>
    
    Backport notes: ieee80211_data_from_8023() hunk has been dropped,
    seems the functional has been removed by RedHat, anyway, not used since 2012.
---
 net/core/skbuff.c        | 14 +++++++++++---
 net/netlink/af_netlink.c |  4 +---
 2 files changed, 12 insertions(+), 6 deletions(-)

Patch hide | download patch | download mbox

diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 4f826dca83104..ccd585789f3d8 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -1251,10 +1251,10 @@  EXPORT_SYMBOL(__pskb_copy);
 int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
 		     gfp_t gfp_mask)
 {
-	int i;
-	u8 *data;
-	int size = nhead + skb_end_offset(skb) + ntail;
+	int i, osize = skb_end_offset(skb);
+	int size = osize + nhead + ntail;
 	long off;
+	u8 *data;
 
 	BUG_ON(nhead < 0);
 
@@ -1316,6 +1316,14 @@  int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
 	skb->hdr_len  = 0;
 	skb->nohdr    = 0;
 	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;
 
 nofrags:
diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c
index efaa94abfc03e..382141c8a0d71 100644
--- a/net/netlink/af_netlink.c
+++ b/net/netlink/af_netlink.c
@@ -1166,9 +1166,7 @@  static struct sk_buff *netlink_trim(struct sk_buff *skb, gfp_t allocation)
 		skb = nskb;
 	}
 
-	if (!pskb_expand_head(skb, 0, -delta, allocation))
-		skb->truesize -= delta;
-
+	pskb_expand_head(skb, 0, -delta, allocation);
 	return skb;
 }