Commit c6d4e63e authored by Elena Reshetova's avatar Elena Reshetova Committed by David S. Miller
Browse files

drivers, net, ethernet: convert mtk_eth.dma_refcnt from atomic_t to refcount_t



atomic_t variables are currently used to implement reference
counters with the following properties:
 - counter is initialized to 1 using atomic_set()
 - a resource is freed upon counter reaching zero
 - once counter reaches zero, its further
   increments aren't allowed
 - counter schema uses basic atomic operations
   (set, inc, inc_not_zero, dec_and_test, etc.)

Such atomic variables should be converted to a newly provided
refcount_t type and API that prevents accidental counter overflows
and underflows. This is important since overflows and underflows
can lead to use-after-free situation and be exploitable.

The variable mtk_eth.dma_refcnt is used as pure reference counter.
Convert it to refcount_t and fix up the operations.

Suggested-by: default avatarKees Cook <keescook@chromium.org>
Reviewed-by: default avatarDavid Windsor <dwindsor@gmail.com>
Reviewed-by: default avatarHans Liljestrand <ishkamiel@gmail.com>
Signed-off-by: default avatarElena Reshetova <elena.reshetova@intel.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent eaf6ab76
Loading
Loading
Loading
Loading
+5 −3
Original line number Diff line number Diff line
@@ -1817,7 +1817,7 @@ static int mtk_open(struct net_device *dev)
	struct mtk_eth *eth = mac->hw;

	/* we run 2 netdevs on the same dma ring so we only bring it up once */
	if (!atomic_read(&eth->dma_refcnt)) {
	if (!refcount_read(&eth->dma_refcnt)) {
		int err = mtk_start_dma(eth);

		if (err)
@@ -1827,8 +1827,10 @@ static int mtk_open(struct net_device *dev)
		napi_enable(&eth->rx_napi);
		mtk_tx_irq_enable(eth, MTK_TX_DONE_INT);
		mtk_rx_irq_enable(eth, MTK_RX_DONE_INT);
		refcount_set(&eth->dma_refcnt, 1);
	}
	atomic_inc(&eth->dma_refcnt);
	else
		refcount_inc(&eth->dma_refcnt);

	phy_start(dev->phydev);
	netif_start_queue(dev);
@@ -1868,7 +1870,7 @@ static int mtk_stop(struct net_device *dev)
	phy_stop(dev->phydev);

	/* only shutdown DMA if this is the last user */
	if (!atomic_dec_and_test(&eth->dma_refcnt))
	if (!refcount_dec_and_test(&eth->dma_refcnt))
		return 0;

	mtk_tx_irq_disable(eth, MTK_TX_DONE_INT);
+3 −1
Original line number Diff line number Diff line
@@ -15,6 +15,8 @@
#ifndef MTK_ETH_H
#define MTK_ETH_H

#include <linux/refcount.h>

#define MTK_QDMA_PAGE_SIZE	2048
#define	MTK_MAX_RX_LENGTH	1536
#define MTK_TX_DMA_BUF_LEN	0x3fff
@@ -632,7 +634,7 @@ struct mtk_eth {
	struct regmap			*pctl;
	u32				chip_id;
	bool				hwlro;
	atomic_t			dma_refcnt;
	refcount_t			dma_refcnt;
	struct mtk_tx_ring		tx_ring;
	struct mtk_rx_ring		rx_ring[MTK_MAX_RX_RING_NUM];
	struct mtk_rx_ring		rx_ring_qdma;