Commit ec764bf083a6ff396234351b51fd236f53c903bf

Authored by Koki Sanagi
Committed by David S. Miller
1 parent 2e4ceec4ed

net: tracepoint of net_dev_xmit sees freed skb and causes panic

Because there is a possibility that skb is kfree_skb()ed and zero cleared
after ndo_start_xmit, we should not see the contents of skb like skb->len and
skb->dev->name after ndo_start_xmit. But trace_net_dev_xmit does that
and causes panic by NULL pointer dereference.
This patch fixes trace_net_dev_xmit not to see the contents of skb directly.

If you want to reproduce this panic,

1. Get tracepoint of net_dev_xmit on
2. Create 2 guests on KVM
2. Make 2 guests use virtio_net
4. Execute netperf from one to another for a long time as a network burden
5. host will panic(It takes about 30 minutes)

Signed-off-by: Koki Sanagi <sanagi.koki@jp.fujitsu.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

Showing 2 changed files with 12 additions and 7 deletions Side-by-side Diff

include/trace/events/net.h
... ... @@ -12,22 +12,24 @@
12 12 TRACE_EVENT(net_dev_xmit,
13 13  
14 14 TP_PROTO(struct sk_buff *skb,
15   - int rc),
  15 + int rc,
  16 + struct net_device *dev,
  17 + unsigned int skb_len),
16 18  
17   - TP_ARGS(skb, rc),
  19 + TP_ARGS(skb, rc, dev, skb_len),
18 20  
19 21 TP_STRUCT__entry(
20 22 __field( void *, skbaddr )
21 23 __field( unsigned int, len )
22 24 __field( int, rc )
23   - __string( name, skb->dev->name )
  25 + __string( name, dev->name )
24 26 ),
25 27  
26 28 TP_fast_assign(
27 29 __entry->skbaddr = skb;
28   - __entry->len = skb->len;
  30 + __entry->len = skb_len;
29 31 __entry->rc = rc;
30   - __assign_str(name, skb->dev->name);
  32 + __assign_str(name, dev->name);
31 33 ),
32 34  
33 35 TP_printk("dev=%s skbaddr=%p len=%u rc=%d",
... ... @@ -2096,6 +2096,7 @@
2096 2096 {
2097 2097 const struct net_device_ops *ops = dev->netdev_ops;
2098 2098 int rc = NETDEV_TX_OK;
  2099 + unsigned int skb_len;
2099 2100  
2100 2101 if (likely(!skb->next)) {
2101 2102 u32 features;
2102 2103  
... ... @@ -2146,8 +2147,9 @@
2146 2147 }
2147 2148 }
2148 2149  
  2150 + skb_len = skb->len;
2149 2151 rc = ops->ndo_start_xmit(skb, dev);
2150   - trace_net_dev_xmit(skb, rc);
  2152 + trace_net_dev_xmit(skb, rc, dev, skb_len);
2151 2153 if (rc == NETDEV_TX_OK)
2152 2154 txq_trans_update(txq);
2153 2155 return rc;
2154 2156  
... ... @@ -2167,8 +2169,9 @@
2167 2169 if (dev->priv_flags & IFF_XMIT_DST_RELEASE)
2168 2170 skb_dst_drop(nskb);
2169 2171  
  2172 + skb_len = nskb->len;
2170 2173 rc = ops->ndo_start_xmit(nskb, dev);
2171   - trace_net_dev_xmit(nskb, rc);
  2174 + trace_net_dev_xmit(nskb, rc, dev, skb_len);
2172 2175 if (unlikely(rc != NETDEV_TX_OK)) {
2173 2176 if (rc & ~NETDEV_TX_MASK)
2174 2177 goto out_kfree_gso_skb;