aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/spider_net.c
diff options
context:
space:
mode:
authorLinas Vepstas <linas@austin.ibm.com>2007-02-20 17:41:03 -0500
committerJeff Garzik <jeff@garzik.org>2007-02-27 04:16:03 -0500
commitd9c199ee781fa874e6feb4c56ae3d0e19f7f82a6 (patch)
tree6f4975a6b8f8aa00dc2d6cf6463a385f9d736a2c /drivers/net/spider_net.c
parent4cb6f9e57d5d7c26d08809c1ce6310c8a7dc96d2 (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.c23
1 files changed, 15 insertions, 8 deletions
diff --git a/drivers/net/spider_net.c b/drivers/net/spider_net.c
index 10f9e29c1bbf..15b0bcaec467 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
682spider_net_prepare_tx_descr(struct spider_net_card *card, 684spider_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
1128bad_desc: 1134bad_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}