mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-24 03:24:55 +08:00
net: stmmac: fix NULL pointer dereference in stmmac_get_tx_hwtstamp
When timestamping is enabled, stmmac_tx_clean will call stmmac_get_tx_hwtstamp to get tx TS. But the skb can be NULL because the last of its tx_skbuff is NULL if this packet frame is filled in more than one descriptors. To fix the issue, change the code: - Store TX skb to the tx_skbuff[] of frame's last segment. - Check skb is not NULL in stmmac_get_tx_hwtstamp. Signed-off-by: Bruce Liu <damuzi000@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
af0bd4e9ba
commit
75e4364f67
@ -51,6 +51,7 @@ static unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
|
|||||||
priv->hw->desc->prepare_tx_desc(desc, 1, bmax, csum, STMMAC_CHAIN_MODE);
|
priv->hw->desc->prepare_tx_desc(desc, 1, bmax, csum, STMMAC_CHAIN_MODE);
|
||||||
|
|
||||||
while (len != 0) {
|
while (len != 0) {
|
||||||
|
priv->tx_skbuff[entry] = NULL;
|
||||||
entry = (++priv->cur_tx) % txsize;
|
entry = (++priv->cur_tx) % txsize;
|
||||||
desc = priv->dma_tx + entry;
|
desc = priv->dma_tx + entry;
|
||||||
|
|
||||||
@ -62,7 +63,6 @@ static unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
|
|||||||
priv->hw->desc->prepare_tx_desc(desc, 0, bmax, csum,
|
priv->hw->desc->prepare_tx_desc(desc, 0, bmax, csum,
|
||||||
STMMAC_CHAIN_MODE);
|
STMMAC_CHAIN_MODE);
|
||||||
priv->hw->desc->set_tx_owner(desc);
|
priv->hw->desc->set_tx_owner(desc);
|
||||||
priv->tx_skbuff[entry] = NULL;
|
|
||||||
len -= bmax;
|
len -= bmax;
|
||||||
i++;
|
i++;
|
||||||
} else {
|
} else {
|
||||||
@ -73,7 +73,6 @@ static unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
|
|||||||
priv->hw->desc->prepare_tx_desc(desc, 0, len, csum,
|
priv->hw->desc->prepare_tx_desc(desc, 0, len, csum,
|
||||||
STMMAC_CHAIN_MODE);
|
STMMAC_CHAIN_MODE);
|
||||||
priv->hw->desc->set_tx_owner(desc);
|
priv->hw->desc->set_tx_owner(desc);
|
||||||
priv->tx_skbuff[entry] = NULL;
|
|
||||||
len = 0;
|
len = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -58,6 +58,7 @@ static unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
|
|||||||
priv->hw->desc->prepare_tx_desc(desc, 1, bmax, csum,
|
priv->hw->desc->prepare_tx_desc(desc, 1, bmax, csum,
|
||||||
STMMAC_RING_MODE);
|
STMMAC_RING_MODE);
|
||||||
wmb();
|
wmb();
|
||||||
|
priv->tx_skbuff[entry] = NULL;
|
||||||
entry = (++priv->cur_tx) % txsize;
|
entry = (++priv->cur_tx) % txsize;
|
||||||
|
|
||||||
if (priv->extend_desc)
|
if (priv->extend_desc)
|
||||||
@ -73,7 +74,6 @@ static unsigned int stmmac_jumbo_frm(void *p, struct sk_buff *skb, int csum)
|
|||||||
STMMAC_RING_MODE);
|
STMMAC_RING_MODE);
|
||||||
wmb();
|
wmb();
|
||||||
priv->hw->desc->set_tx_owner(desc);
|
priv->hw->desc->set_tx_owner(desc);
|
||||||
priv->tx_skbuff[entry] = NULL;
|
|
||||||
} else {
|
} else {
|
||||||
desc->des2 = dma_map_single(priv->device, skb->data,
|
desc->des2 = dma_map_single(priv->device, skb->data,
|
||||||
nopaged_len, DMA_TO_DEVICE);
|
nopaged_len, DMA_TO_DEVICE);
|
||||||
|
@ -334,7 +334,7 @@ static void stmmac_get_tx_hwtstamp(struct stmmac_priv *priv,
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
/* exit if skb doesn't support hw tstamp */
|
/* exit if skb doesn't support hw tstamp */
|
||||||
if (likely(!(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)))
|
if (likely(!skb || !(skb_shinfo(skb)->tx_flags & SKBTX_IN_PROGRESS)))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (priv->adv_ts)
|
if (priv->adv_ts)
|
||||||
@ -1081,21 +1081,24 @@ static void dma_free_tx_skbufs(struct stmmac_priv *priv)
|
|||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < priv->dma_tx_size; i++) {
|
for (i = 0; i < priv->dma_tx_size; i++) {
|
||||||
if (priv->tx_skbuff[i] != NULL) {
|
struct dma_desc *p;
|
||||||
struct dma_desc *p;
|
|
||||||
if (priv->extend_desc)
|
|
||||||
p = &((priv->dma_etx + i)->basic);
|
|
||||||
else
|
|
||||||
p = priv->dma_tx + i;
|
|
||||||
|
|
||||||
if (priv->tx_skbuff_dma[i])
|
if (priv->extend_desc)
|
||||||
dma_unmap_single(priv->device,
|
p = &((priv->dma_etx + i)->basic);
|
||||||
priv->tx_skbuff_dma[i],
|
else
|
||||||
priv->hw->desc->get_tx_len(p),
|
p = priv->dma_tx + i;
|
||||||
DMA_TO_DEVICE);
|
|
||||||
|
if (priv->tx_skbuff_dma[i]) {
|
||||||
|
dma_unmap_single(priv->device,
|
||||||
|
priv->tx_skbuff_dma[i],
|
||||||
|
priv->hw->desc->get_tx_len(p),
|
||||||
|
DMA_TO_DEVICE);
|
||||||
|
priv->tx_skbuff_dma[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (priv->tx_skbuff[i] != NULL) {
|
||||||
dev_kfree_skb_any(priv->tx_skbuff[i]);
|
dev_kfree_skb_any(priv->tx_skbuff[i]);
|
||||||
priv->tx_skbuff[i] = NULL;
|
priv->tx_skbuff[i] = NULL;
|
||||||
priv->tx_skbuff_dma[i] = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1867,8 +1870,6 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||||||
|
|
||||||
first = desc;
|
first = desc;
|
||||||
|
|
||||||
priv->tx_skbuff[entry] = skb;
|
|
||||||
|
|
||||||
/* To program the descriptors according to the size of the frame */
|
/* To program the descriptors according to the size of the frame */
|
||||||
if (priv->mode == STMMAC_RING_MODE) {
|
if (priv->mode == STMMAC_RING_MODE) {
|
||||||
is_jumbo = priv->hw->ring->is_jumbo_frm(skb->len,
|
is_jumbo = priv->hw->ring->is_jumbo_frm(skb->len,
|
||||||
@ -1896,6 +1897,7 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||||||
const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
|
const skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
|
||||||
int len = skb_frag_size(frag);
|
int len = skb_frag_size(frag);
|
||||||
|
|
||||||
|
priv->tx_skbuff[entry] = NULL;
|
||||||
entry = (++priv->cur_tx) % txsize;
|
entry = (++priv->cur_tx) % txsize;
|
||||||
if (priv->extend_desc)
|
if (priv->extend_desc)
|
||||||
desc = (struct dma_desc *)(priv->dma_etx + entry);
|
desc = (struct dma_desc *)(priv->dma_etx + entry);
|
||||||
@ -1905,7 +1907,6 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||||||
desc->des2 = skb_frag_dma_map(priv->device, frag, 0, len,
|
desc->des2 = skb_frag_dma_map(priv->device, frag, 0, len,
|
||||||
DMA_TO_DEVICE);
|
DMA_TO_DEVICE);
|
||||||
priv->tx_skbuff_dma[entry] = desc->des2;
|
priv->tx_skbuff_dma[entry] = desc->des2;
|
||||||
priv->tx_skbuff[entry] = NULL;
|
|
||||||
priv->hw->desc->prepare_tx_desc(desc, 0, len, csum_insertion,
|
priv->hw->desc->prepare_tx_desc(desc, 0, len, csum_insertion,
|
||||||
priv->mode);
|
priv->mode);
|
||||||
wmb();
|
wmb();
|
||||||
@ -1913,6 +1914,8 @@ static netdev_tx_t stmmac_xmit(struct sk_buff *skb, struct net_device *dev)
|
|||||||
wmb();
|
wmb();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
priv->tx_skbuff[entry] = skb;
|
||||||
|
|
||||||
/* Finalize the latest segment. */
|
/* Finalize the latest segment. */
|
||||||
priv->hw->desc->close_tx_desc(desc);
|
priv->hw->desc->close_tx_desc(desc);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user