Commit 335c9017 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull spi fixes from Mark Brown:
 "There are two core fixes here. One is from Johan dealing with an issue
  introduced by a devm_ API usage update causing things to be freed
  earlier than they had earlier when we fail to register a device,
  another from Danilo avoids unlocked acccess to data by converting to
  use a driver core API.

  We also have a few relatively minor driver specific fixes"

* tag 'spi-fix-v7.0-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/broonie/spi:
  spi: spi-fsl-lpspi: fix teardown order issue (UAF)
  spi: fix use-after-free on managed registration failure
  spi: use generic driver_override infrastructure
  spi: meson-spicc: Fix double-put in remove path
  spi: sn-f-ospi: Use devm_mutex_init() to simplify code
  spi: sn-f-ospi: Fix resource leak in f_ospi_probe()
parents cd0bbd5a b341c117
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -1009,7 +1009,7 @@ static int fsl_lpspi_probe(struct platform_device *pdev)
		enable_irq(irq);
	}

	ret = devm_spi_register_controller(&pdev->dev, controller);
	ret = spi_register_controller(controller);
	if (ret < 0) {
		dev_err_probe(&pdev->dev, ret, "spi_register_controller error\n");
		goto free_dma;
@@ -1035,6 +1035,7 @@ static void fsl_lpspi_remove(struct platform_device *pdev)
	struct fsl_lpspi_data *fsl_lpspi =
				spi_controller_get_devdata(controller);

	spi_unregister_controller(controller);
	fsl_lpspi_dma_exit(controller);

	pm_runtime_dont_use_autosuspend(fsl_lpspi->dev);
+0 −2
Original line number Diff line number Diff line
@@ -1101,8 +1101,6 @@ static void meson_spicc_remove(struct platform_device *pdev)

	/* Disable SPI */
	writel(0, spicc->base + SPICC_CONREG);

	spi_controller_put(spicc->host);
}

static const struct meson_spicc_data meson_spicc_gx_data = {
+10 −32
Original line number Diff line number Diff line
@@ -612,7 +612,7 @@ static int f_ospi_probe(struct platform_device *pdev)
	u32 num_cs = OSPI_NUM_CS;
	int ret;

	ctlr = spi_alloc_host(dev, sizeof(*ospi));
	ctlr = devm_spi_alloc_host(dev, sizeof(*ospi));
	if (!ctlr)
		return -ENOMEM;

@@ -635,43 +635,22 @@ static int f_ospi_probe(struct platform_device *pdev)
	platform_set_drvdata(pdev, ospi);

	ospi->base = devm_platform_ioremap_resource(pdev, 0);
	if (IS_ERR(ospi->base)) {
		ret = PTR_ERR(ospi->base);
		goto err_put_ctlr;
	}
	if (IS_ERR(ospi->base))
		return PTR_ERR(ospi->base);

	ospi->clk = devm_clk_get_enabled(dev, NULL);
	if (IS_ERR(ospi->clk)) {
		ret = PTR_ERR(ospi->clk);
		goto err_put_ctlr;
	}
	if (IS_ERR(ospi->clk))
		return PTR_ERR(ospi->clk);

	mutex_init(&ospi->mlock);

	ret = f_ospi_init(ospi);
	ret = devm_mutex_init(dev, &ospi->mlock);
	if (ret)
		goto err_destroy_mutex;
		return ret;

	ret = devm_spi_register_controller(dev, ctlr);
	ret = f_ospi_init(ospi);
	if (ret)
		goto err_destroy_mutex;

	return 0;

err_destroy_mutex:
	mutex_destroy(&ospi->mlock);

err_put_ctlr:
	spi_controller_put(ctlr);

		return ret;
}

static void f_ospi_remove(struct platform_device *pdev)
{
	struct f_ospi *ospi = platform_get_drvdata(pdev);

	mutex_destroy(&ospi->mlock);
	return devm_spi_register_controller(dev, ctlr);
}

static const struct of_device_id f_ospi_dt_ids[] = {
@@ -686,7 +665,6 @@ static struct platform_driver f_ospi_driver = {
		.of_match_table = f_ospi_dt_ids,
	},
	.probe = f_ospi_probe,
	.remove = f_ospi_remove,
};
module_platform_driver(f_ospi_driver);

+19 −13
Original line number Diff line number Diff line
@@ -50,7 +50,6 @@ static void spidev_release(struct device *dev)
	struct spi_device	*spi = to_spi_device(dev);

	spi_controller_put(spi->controller);
	kfree(spi->driver_override);
	free_percpu(spi->pcpu_statistics);
	kfree(spi);
}
@@ -73,10 +72,9 @@ static ssize_t driver_override_store(struct device *dev,
				     struct device_attribute *a,
				     const char *buf, size_t count)
{
	struct spi_device *spi = to_spi_device(dev);
	int ret;

	ret = driver_set_override(dev, &spi->driver_override, buf, count);
	ret = __device_set_driver_override(dev, buf, count);
	if (ret)
		return ret;

@@ -86,13 +84,8 @@ static ssize_t driver_override_store(struct device *dev,
static ssize_t driver_override_show(struct device *dev,
				    struct device_attribute *a, char *buf)
{
	const struct spi_device *spi = to_spi_device(dev);
	ssize_t len;

	device_lock(dev);
	len = sysfs_emit(buf, "%s\n", spi->driver_override ? : "");
	device_unlock(dev);
	return len;
	guard(spinlock)(&dev->driver_override.lock);
	return sysfs_emit(buf, "%s\n", dev->driver_override.name ?: "");
}
static DEVICE_ATTR_RW(driver_override);

@@ -376,10 +369,12 @@ static int spi_match_device(struct device *dev, const struct device_driver *drv)
{
	const struct spi_device	*spi = to_spi_device(dev);
	const struct spi_driver	*sdrv = to_spi_driver(drv);
	int ret;

	/* Check override first, and if set, only use the named driver */
	if (spi->driver_override)
		return strcmp(spi->driver_override, drv->name) == 0;
	ret = device_match_driver_override(dev, drv);
	if (ret >= 0)
		return ret;

	/* Attempt an OF style match */
	if (of_driver_match_device(dev, drv))
@@ -3539,8 +3534,19 @@ int devm_spi_register_controller(struct device *dev,
	if (ret)
		return ret;

	return devm_add_action_or_reset(dev, devm_spi_unregister_controller, ctlr);
	/*
	 * Prevent controller from being freed by spi_unregister_controller()
	 * if devm_add_action_or_reset() fails for a non-devres allocated
	 * controller.
	 */
	spi_controller_get(ctlr);

	ret = devm_add_action_or_reset(dev, devm_spi_unregister_controller, ctlr);

	if (ret == 0 || ctlr->devm_allocated)
		spi_controller_put(ctlr);

	return ret;
}
EXPORT_SYMBOL_GPL(devm_spi_register_controller);

+0 −5
Original line number Diff line number Diff line
@@ -159,10 +159,6 @@ extern void spi_transfer_cs_change_delay_exec(struct spi_message *msg,
 * @modalias: Name of the driver to use with this device, or an alias
 *	for that name.  This appears in the sysfs "modalias" attribute
 *	for driver coldplugging, and in uevents used for hotplugging
 * @driver_override: If the name of a driver is written to this attribute, then
 *	the device will bind to the named driver and only the named driver.
 *	Do not set directly, because core frees it; use driver_set_override() to
 *	set or clear it.
 * @pcpu_statistics: statistics for the spi_device
 * @word_delay: delay to be inserted between consecutive
 *	words of a transfer
@@ -224,7 +220,6 @@ struct spi_device {
	void			*controller_state;
	void			*controller_data;
	char			modalias[SPI_NAME_SIZE];
	const char		*driver_override;

	/* The statistics */
	struct spi_statistics __percpu	*pcpu_statistics;