Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit b7f58686 authored by Stefan Wahren's avatar Stefan Wahren Committed by Greg Kroah-Hartman
Browse files

qca_debug: Prevent crash on TX ring changes



[ Upstream commit f4e6064c97c050bd9904925ff7d53d0c9954fc7b ]

The qca_spi driver stop and restart the SPI kernel thread
(via ndo_stop & ndo_open) in case of TX ring changes. This is
a big issue because it allows userspace to prevent restart of
the SPI kernel thread (via signals). A subsequent change of
TX ring wrongly assume a valid spi_thread pointer which result
in a crash.

So prevent this by stopping the network traffic handling and
temporary park the SPI thread.

Fixes: 291ab06e ("net: qualcomm: new Ethernet over SPI driver for QCA7000")
Signed-off-by: default avatarStefan Wahren <wahrenst@gmx.net>
Link: https://lore.kernel.org/r/20231206141222.52029-2-wahrenst@gmx.net


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
parent 9354e0ac
Loading
Loading
Loading
Loading
+4 −5
Original line number Diff line number Diff line
@@ -258,7 +258,6 @@ qcaspi_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ring)
static int
qcaspi_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ring)
{
	const struct net_device_ops *ops = dev->netdev_ops;
	struct qcaspi *qca = netdev_priv(dev);

	if ((ring->rx_pending) ||
@@ -266,14 +265,14 @@ qcaspi_set_ringparam(struct net_device *dev, struct ethtool_ringparam *ring)
	    (ring->rx_jumbo_pending))
		return -EINVAL;

	if (netif_running(dev))
		ops->ndo_stop(dev);
	if (qca->spi_thread)
		kthread_park(qca->spi_thread);

	qca->txr.count = max_t(u32, ring->tx_pending, TX_RING_MIN_LEN);
	qca->txr.count = min_t(u16, qca->txr.count, TX_RING_MAX_LEN);

	if (netif_running(dev))
		ops->ndo_open(dev);
	if (qca->spi_thread)
		kthread_unpark(qca->spi_thread);

	return 0;
}
+12 −0
Original line number Diff line number Diff line
@@ -573,6 +573,18 @@ qcaspi_spi_thread(void *data)
	netdev_info(qca->net_dev, "SPI thread created\n");
	while (!kthread_should_stop()) {
		set_current_state(TASK_INTERRUPTIBLE);
		if (kthread_should_park()) {
			netif_tx_disable(qca->net_dev);
			netif_carrier_off(qca->net_dev);
			qcaspi_flush_tx_ring(qca);
			kthread_parkme();
			if (qca->sync == QCASPI_SYNC_READY) {
				netif_carrier_on(qca->net_dev);
				netif_wake_queue(qca->net_dev);
			}
			continue;
		}

		if ((qca->intr_req == qca->intr_svc) &&
		    !qca->txr.skb[qca->txr.head])
			schedule();