There's a race in pktgen which can lead to a double free of a pktgen_dev's skb. If a worker thread is in the midst of doing fill_packet(), and the controlling thread gets a "stop" message, the already freed skb can be freed once again in pktgen_stop_device().
This patch removes the race by setting the pktgen_dev's skb to NULL before freeing it. Signed-off-by: Arthur Kepner <[EMAIL PROTECTED]> --- diff --git a/net/core/pktgen.c b/net/core/pktgen.c --- a/net/core/pktgen.c +++ b/net/core/pktgen.c @@ -2431,6 +2431,8 @@ static void show_results(struct pktgen_d static int pktgen_stop_device(struct pktgen_dev *pkt_dev) { + struct sk_buff * old_skb = NULL; + int nr_frags = -1; if (!pkt_dev->running) { printk("pktgen: interface: %s is already stopped\n", pkt_dev->ifname); @@ -2440,13 +2442,14 @@ static int pktgen_stop_device(struct pkt pkt_dev->stopped_at = getCurUs(); pkt_dev->running = 0; - show_results(pkt_dev, skb_shinfo(pkt_dev->skb)->nr_frags); + if ((old_skb = pkt_dev->skb) != NULL) { + pkt_dev->skb = NULL; + nr_frags = skb_shinfo(old_skb)->nr_frags; + kfree_skb(old_skb); + } - if (pkt_dev->skb) - kfree_skb(pkt_dev->skb); + show_results(pkt_dev, nr_frags); - pkt_dev->skb = NULL; - return 0; } @@ -2566,9 +2569,13 @@ static __inline__ void pktgen_xmit(struc if (pkt_dev->last_ok || !pkt_dev->skb) { if ((++pkt_dev->clone_count >= pkt_dev->clone_skb ) || (!pkt_dev->skb)) { + struct sk_buff * old_skb = NULL; + /* build a new pkt */ - if (pkt_dev->skb) - kfree_skb(pkt_dev->skb); + if ((old_skb = pkt_dev->skb) != NULL) { + pkt_dev->skb = NULL; + kfree_skb(old_skb); + } pkt_dev->skb = fill_packet(odev, pkt_dev); if (pkt_dev->skb == NULL) { - To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html