Skip to content

Commit 9343894

Browse files
khoroshilovgregkh
authored andcommitted
net: adaptec: starfire: add checks for dma mapping errors
[ Upstream commit d1156b489fa734d1af763d6a07b1637c01bb0aed ] init_ring(), refill_rx_ring() and start_tx() don't check if mapping dma memory succeed. The patch adds the checks and failure handling. Found by Linux Driver Verification project (linuxtesting.org). Signed-off-by: Alexey Khoroshilov <khoroshilov@ispras.ru> Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Sasha Levin <alexander.levin@verizon.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 3926d04 commit 9343894

1 file changed

Lines changed: 43 additions & 2 deletions

File tree

drivers/net/ethernet/adaptec/starfire.c

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1153,6 +1153,12 @@ static void init_ring(struct net_device *dev)
11531153
if (skb == NULL)
11541154
break;
11551155
np->rx_info[i].mapping = pci_map_single(np->pci_dev, skb->data, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
1156+
if (pci_dma_mapping_error(np->pci_dev,
1157+
np->rx_info[i].mapping)) {
1158+
dev_kfree_skb(skb);
1159+
np->rx_info[i].skb = NULL;
1160+
break;
1161+
}
11561162
/* Grrr, we cannot offset to correctly align the IP header. */
11571163
np->rx_ring[i].rxaddr = cpu_to_dma(np->rx_info[i].mapping | RxDescValid);
11581164
}
@@ -1183,8 +1189,9 @@ static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev)
11831189
{
11841190
struct netdev_private *np = netdev_priv(dev);
11851191
unsigned int entry;
1192+
unsigned int prev_tx;
11861193
u32 status;
1187-
int i;
1194+
int i, j;
11881195

11891196
/*
11901197
* be cautious here, wrapping the queue has weird semantics
@@ -1202,6 +1209,7 @@ static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev)
12021209
}
12031210
#endif /* ZEROCOPY && HAS_BROKEN_FIRMWARE */
12041211

1212+
prev_tx = np->cur_tx;
12051213
entry = np->cur_tx % TX_RING_SIZE;
12061214
for (i = 0; i < skb_num_frags(skb); i++) {
12071215
int wrap_ring = 0;
@@ -1235,6 +1243,11 @@ static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev)
12351243
skb_frag_size(this_frag),
12361244
PCI_DMA_TODEVICE);
12371245
}
1246+
if (pci_dma_mapping_error(np->pci_dev,
1247+
np->tx_info[entry].mapping)) {
1248+
dev->stats.tx_dropped++;
1249+
goto err_out;
1250+
}
12381251

12391252
np->tx_ring[entry].addr = cpu_to_dma(np->tx_info[entry].mapping);
12401253
np->tx_ring[entry].status = cpu_to_le32(status);
@@ -1269,8 +1282,30 @@ static netdev_tx_t start_tx(struct sk_buff *skb, struct net_device *dev)
12691282
netif_stop_queue(dev);
12701283

12711284
return NETDEV_TX_OK;
1272-
}
12731285

1286+
err_out:
1287+
entry = prev_tx % TX_RING_SIZE;
1288+
np->tx_info[entry].skb = NULL;
1289+
if (i > 0) {
1290+
pci_unmap_single(np->pci_dev,
1291+
np->tx_info[entry].mapping,
1292+
skb_first_frag_len(skb),
1293+
PCI_DMA_TODEVICE);
1294+
np->tx_info[entry].mapping = 0;
1295+
entry = (entry + np->tx_info[entry].used_slots) % TX_RING_SIZE;
1296+
for (j = 1; j < i; j++) {
1297+
pci_unmap_single(np->pci_dev,
1298+
np->tx_info[entry].mapping,
1299+
skb_frag_size(
1300+
&skb_shinfo(skb)->frags[j-1]),
1301+
PCI_DMA_TODEVICE);
1302+
entry++;
1303+
}
1304+
}
1305+
dev_kfree_skb_any(skb);
1306+
np->cur_tx = prev_tx;
1307+
return NETDEV_TX_OK;
1308+
}
12741309

12751310
/* The interrupt handler does all of the Rx thread work and cleans up
12761311
after the Tx thread. */
@@ -1570,6 +1605,12 @@ static void refill_rx_ring(struct net_device *dev)
15701605
break; /* Better luck next round. */
15711606
np->rx_info[entry].mapping =
15721607
pci_map_single(np->pci_dev, skb->data, np->rx_buf_sz, PCI_DMA_FROMDEVICE);
1608+
if (pci_dma_mapping_error(np->pci_dev,
1609+
np->rx_info[entry].mapping)) {
1610+
dev_kfree_skb(skb);
1611+
np->rx_info[entry].skb = NULL;
1612+
break;
1613+
}
15731614
np->rx_ring[entry].rxaddr =
15741615
cpu_to_dma(np->rx_info[entry].mapping | RxDescValid);
15751616
}

0 commit comments

Comments
 (0)