Commit ec764bf0 authored by Koki Sanagi's avatar Koki Sanagi Committed by David S. Miller

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: default avatarKoki Sanagi <sanagi.koki@jp.fujitsu.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 2e4ceec4
...@@ -12,22 +12,24 @@ ...@@ -12,22 +12,24 @@
TRACE_EVENT(net_dev_xmit, TRACE_EVENT(net_dev_xmit,
TP_PROTO(struct sk_buff *skb, TP_PROTO(struct sk_buff *skb,
int rc), int rc,
struct net_device *dev,
unsigned int skb_len),
TP_ARGS(skb, rc), TP_ARGS(skb, rc, dev, skb_len),
TP_STRUCT__entry( TP_STRUCT__entry(
__field( void *, skbaddr ) __field( void *, skbaddr )
__field( unsigned int, len ) __field( unsigned int, len )
__field( int, rc ) __field( int, rc )
__string( name, skb->dev->name ) __string( name, dev->name )
), ),
TP_fast_assign( TP_fast_assign(
__entry->skbaddr = skb; __entry->skbaddr = skb;
__entry->len = skb->len; __entry->len = skb_len;
__entry->rc = rc; __entry->rc = rc;
__assign_str(name, skb->dev->name); __assign_str(name, dev->name);
), ),
TP_printk("dev=%s skbaddr=%p len=%u rc=%d", TP_printk("dev=%s skbaddr=%p len=%u rc=%d",
......
...@@ -2096,6 +2096,7 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, ...@@ -2096,6 +2096,7 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
{ {
const struct net_device_ops *ops = dev->netdev_ops; const struct net_device_ops *ops = dev->netdev_ops;
int rc = NETDEV_TX_OK; int rc = NETDEV_TX_OK;
unsigned int skb_len;
if (likely(!skb->next)) { if (likely(!skb->next)) {
u32 features; u32 features;
...@@ -2146,8 +2147,9 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, ...@@ -2146,8 +2147,9 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
} }
} }
skb_len = skb->len;
rc = ops->ndo_start_xmit(skb, dev); rc = ops->ndo_start_xmit(skb, dev);
trace_net_dev_xmit(skb, rc); trace_net_dev_xmit(skb, rc, dev, skb_len);
if (rc == NETDEV_TX_OK) if (rc == NETDEV_TX_OK)
txq_trans_update(txq); txq_trans_update(txq);
return rc; return rc;
...@@ -2167,8 +2169,9 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev, ...@@ -2167,8 +2169,9 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
if (dev->priv_flags & IFF_XMIT_DST_RELEASE) if (dev->priv_flags & IFF_XMIT_DST_RELEASE)
skb_dst_drop(nskb); skb_dst_drop(nskb);
skb_len = nskb->len;
rc = ops->ndo_start_xmit(nskb, dev); rc = ops->ndo_start_xmit(nskb, dev);
trace_net_dev_xmit(nskb, rc); trace_net_dev_xmit(nskb, rc, dev, skb_len);
if (unlikely(rc != NETDEV_TX_OK)) { if (unlikely(rc != NETDEV_TX_OK)) {
if (rc & ~NETDEV_TX_MASK) if (rc & ~NETDEV_TX_MASK)
goto out_kfree_gso_skb; goto out_kfree_gso_skb;
......
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