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

Reply via email to