diff options
author | Linas Vepstas <linas@austin.ibm.com> | 2007-02-20 17:41:03 -0500 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2007-02-27 04:16:03 -0500 |
commit | d9c199ee781fa874e6feb4c56ae3d0e19f7f82a6 (patch) | |
tree | 6f4975a6b8f8aa00dc2d6cf6463a385f9d736a2c /drivers/net/spider_net.c | |
parent | 4cb6f9e57d5d7c26d08809c1ce6310c8a7dc96d2 (diff) |
spidernet: fix racy double-free of skb
It appears that under certain circumstances, a race will result
in a double-free of an skb. This patch null's out the skb pointer
upon the skb free, avoiding the inadvertent deref of bogus data.
The next patch fixes the actual race.
Signed-off-by: Linas Vepstas <linas@austin.ibm.com>
Cc: Jens Osterkamp <Jens.Osterkamp@de.ibm.com>
Cc: Kou Ishizaki <kou.ishizaki@toshiba.co.jp>
Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/net/spider_net.c')
-rw-r--r-- | drivers/net/spider_net.c | 23 |
1 files changed, 15 insertions, 8 deletions
diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c index 10f9e29c1bb..15b0bcaec46 100644 --- a/drivers/net/spider_net.c +++ b/drivers/net/spider_net.c | |||
@@ -396,10 +396,11 @@ spider_net_free_rx_chain_contents(struct spider_net_card *card) | |||
396 | descr = card->rx_chain.head; | 396 | descr = card->rx_chain.head; |
397 | do { | 397 | do { |
398 | if (descr->skb) { | 398 | if (descr->skb) { |
399 | dev_kfree_skb(descr->skb); | ||
400 | pci_unmap_single(card->pdev, descr->hwdescr->buf_addr, | 399 | pci_unmap_single(card->pdev, descr->hwdescr->buf_addr, |
401 | SPIDER_NET_MAX_FRAME, | 400 | SPIDER_NET_MAX_FRAME, |
402 | PCI_DMA_BIDIRECTIONAL); | 401 | PCI_DMA_BIDIRECTIONAL); |
402 | dev_kfree_skb(descr->skb); | ||
403 | descr->skb = NULL; | ||
403 | } | 404 | } |
404 | descr = descr->next; | 405 | descr = descr->next; |
405 | } while (descr != card->rx_chain.head); | 406 | } while (descr != card->rx_chain.head); |
@@ -453,6 +454,7 @@ spider_net_prepare_rx_descr(struct spider_net_card *card, | |||
453 | SPIDER_NET_MAX_FRAME, PCI_DMA_FROMDEVICE); | 454 | SPIDER_NET_MAX_FRAME, PCI_DMA_FROMDEVICE); |
454 | if (pci_dma_mapping_error(buf)) { | 455 | if (pci_dma_mapping_error(buf)) { |
455 | dev_kfree_skb_any(descr->skb); | 456 | dev_kfree_skb_any(descr->skb); |
457 | descr->skb = NULL; | ||
456 | if (netif_msg_rx_err(card) && net_ratelimit()) | 458 | if (netif_msg_rx_err(card) && net_ratelimit()) |
457 | pr_err("Could not iommu-map rx buffer\n"); | 459 | pr_err("Could not iommu-map rx buffer\n"); |
458 | card->spider_stats.rx_iommu_map_error++; | 460 | card->spider_stats.rx_iommu_map_error++; |
@@ -682,6 +684,7 @@ static int | |||
682 | spider_net_prepare_tx_descr(struct spider_net_card *card, | 684 | spider_net_prepare_tx_descr(struct spider_net_card *card, |
683 | struct sk_buff *skb) | 685 | struct sk_buff *skb) |
684 | { | 686 | { |
687 | struct spider_net_descr_chain *chain = &card->tx_chain; | ||
685 | struct spider_net_descr *descr; | 688 | struct spider_net_descr *descr; |
686 | struct spider_net_hw_descr *hwdescr; | 689 | struct spider_net_hw_descr *hwdescr; |
687 | dma_addr_t buf; | 690 | dma_addr_t buf; |
@@ -696,10 +699,15 @@ spider_net_prepare_tx_descr(struct spider_net_card *card, | |||
696 | return -ENOMEM; | 699 | return -ENOMEM; |
697 | } | 700 | } |
698 | 701 | ||
699 | spin_lock_irqsave(&card->tx_chain.lock, flags); | 702 | spin_lock_irqsave(&chain->lock, flags); |
700 | descr = card->tx_chain.head; | 703 | descr = card->tx_chain.head; |
704 | if (descr->next == chain->tail->prev) { | ||
705 | spin_unlock_irqrestore(&chain->lock, flags); | ||
706 | pci_unmap_single(card->pdev, buf, skb->len, PCI_DMA_TODEVICE); | ||
707 | return -ENOMEM; | ||
708 | } | ||
701 | hwdescr = descr->hwdescr; | 709 | hwdescr = descr->hwdescr; |
702 | card->tx_chain.head = descr->next; | 710 | chain->head = descr->next; |
703 | 711 | ||
704 | descr->skb = skb; | 712 | descr->skb = skb; |
705 | hwdescr->buf_addr = buf; | 713 | hwdescr->buf_addr = buf; |
@@ -709,7 +717,7 @@ spider_net_prepare_tx_descr(struct spider_net_card *card, | |||
709 | 717 | ||
710 | hwdescr->dmac_cmd_status = | 718 | hwdescr->dmac_cmd_status = |
711 | SPIDER_NET_DESCR_CARDOWNED | SPIDER_NET_DMAC_NOCS; | 719 | SPIDER_NET_DESCR_CARDOWNED | SPIDER_NET_DMAC_NOCS; |
712 | spin_unlock_irqrestore(&card->tx_chain.lock, flags); | 720 | spin_unlock_irqrestore(&chain->lock, flags); |
713 | 721 | ||
714 | if (skb->protocol == htons(ETH_P_IP)) | 722 | if (skb->protocol == htons(ETH_P_IP)) |
715 | switch (skb->nh.iph->protocol) { | 723 | switch (skb->nh.iph->protocol) { |
@@ -838,6 +846,7 @@ spider_net_release_tx_chain(struct spider_net_card *card, int brutal) | |||
838 | chain->tail = descr->next; | 846 | chain->tail = descr->next; |
839 | hwdescr->dmac_cmd_status |= SPIDER_NET_DESCR_NOT_IN_USE; | 847 | hwdescr->dmac_cmd_status |= SPIDER_NET_DESCR_NOT_IN_USE; |
840 | skb = descr->skb; | 848 | skb = descr->skb; |
849 | descr->skb = NULL; | ||
841 | buf_addr = hwdescr->buf_addr; | 850 | buf_addr = hwdescr->buf_addr; |
842 | spin_unlock_irqrestore(&chain->lock, flags); | 851 | spin_unlock_irqrestore(&chain->lock, flags); |
843 | 852 | ||
@@ -903,13 +912,10 @@ spider_net_xmit(struct sk_buff *skb, struct net_device *netdev) | |||
903 | { | 912 | { |
904 | int cnt; | 913 | int cnt; |
905 | struct spider_net_card *card = netdev_priv(netdev); | 914 | struct spider_net_card *card = netdev_priv(netdev); |
906 | struct spider_net_descr_chain *chain = &card->tx_chain; | ||
907 | 915 | ||
908 | spider_net_release_tx_chain(card, 0); | 916 | spider_net_release_tx_chain(card, 0); |
909 | 917 | ||
910 | if ((chain->head->next == chain->tail->prev) || | 918 | if (spider_net_prepare_tx_descr(card, skb) != 0) { |
911 | (spider_net_prepare_tx_descr(card, skb) != 0)) { | ||
912 | |||
913 | card->netdev_stats.tx_dropped++; | 919 | card->netdev_stats.tx_dropped++; |
914 | netif_stop_queue(netdev); | 920 | netif_stop_queue(netdev); |
915 | return NETDEV_TX_BUSY; | 921 | return NETDEV_TX_BUSY; |
@@ -1127,6 +1133,7 @@ spider_net_decode_one_descr(struct spider_net_card *card) | |||
1127 | 1133 | ||
1128 | bad_desc: | 1134 | bad_desc: |
1129 | dev_kfree_skb_irq(descr->skb); | 1135 | dev_kfree_skb_irq(descr->skb); |
1136 | descr->skb = NULL; | ||
1130 | hwdescr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE; | 1137 | hwdescr->dmac_cmd_status = SPIDER_NET_DESCR_NOT_IN_USE; |
1131 | return 0; | 1138 | return 0; |
1132 | } | 1139 | } |