Commit 53bc3e1f authored by Zeng Heng's avatar Zeng Heng
Browse files

spi: fix kabi breakage in struct spi_controller

hulk inclusion
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/I9RBZI


CVE: CVE-2021-47469

--------------------------------

Move struct mutex add_lock from struct spi_controller to struct
device in case of kabi breakage in struct spi_controller.

Fixes: 6098475d ("spi: Fix deadlock when adding SPI controllers on SPI buses")
Signed-off-by: default avatarZeng Heng <zengheng4@huawei.com>
parent 0003ab2f
Loading
Loading
Loading
Loading
+27 −11
Original line number Diff line number Diff line
@@ -529,7 +529,7 @@ int spi_add_device(struct spi_device *spi)
	 * chipselect **BEFORE** we call setup(), else we'll trash
	 * its configuration.  Lock against concurrent add() calls.
	 */
	mutex_lock(&ctlr->add_lock);
	mutex_lock(ctlr->dev.add_lock);

	status = bus_for_each_dev(&spi_bus_type, NULL, spi, spi_dev_check);
	if (status) {
@@ -568,7 +568,7 @@ int spi_add_device(struct spi_device *spi)
		dev_dbg(dev, "registered child %s\n", dev_name(&spi->dev));

done:
	mutex_unlock(&ctlr->add_lock);
	mutex_unlock(ctlr->dev.add_lock);
	return status;
}
EXPORT_SYMBOL_GPL(spi_add_device);
@@ -2152,6 +2152,10 @@ int spi_register_controller(struct spi_controller *ctlr)
			return status;
	}

	ctlr->dev.add_lock = kmalloc(sizeof(struct mutex), GFP_KERNEL);
	if (!ctlr->dev.add_lock)
		return -ENOMEM;

	/* even if it's just one always-selected device, there must
	 * be at least one chipselect
	 */
@@ -2163,8 +2167,10 @@ int spi_register_controller(struct spi_controller *ctlr)
		id = idr_alloc(&spi_master_idr, ctlr, ctlr->bus_num,
			ctlr->bus_num + 1, GFP_KERNEL);
		mutex_unlock(&board_lock);
		if (WARN(id < 0, "couldn't get idr"))
			return id == -ENOSPC ? -EBUSY : id;
		if (WARN(id < 0, "couldn't get idr")) {
			status = (id == -ENOSPC) ? -EBUSY : id;
			goto done;
		}
		ctlr->bus_num = id;
	} else if (ctlr->dev.of_node) {
		/* allocate dynamic bus number using Linux idr */
@@ -2175,8 +2181,10 @@ int spi_register_controller(struct spi_controller *ctlr)
			id = idr_alloc(&spi_master_idr, ctlr, ctlr->bus_num,
				       ctlr->bus_num + 1, GFP_KERNEL);
			mutex_unlock(&board_lock);
			if (WARN(id < 0, "couldn't get idr"))
				return id == -ENOSPC ? -EBUSY : id;
			if (WARN(id < 0, "couldn't get idr")) {
				status = (id == -ENOSPC) ? -EBUSY : id;
				goto done;
			}
		}
	}
	if (ctlr->bus_num < 0) {
@@ -2190,8 +2198,11 @@ int spi_register_controller(struct spi_controller *ctlr)
		id = idr_alloc(&spi_master_idr, ctlr, first_dynamic,
			       0, GFP_KERNEL);
		mutex_unlock(&board_lock);
		if (WARN(id < 0, "couldn't get idr"))
			return id;
		if (WARN(id < 0, "couldn't get idr")) {
			status = id;
			goto done;
		}

		ctlr->bus_num = id;
	}
	INIT_LIST_HEAD(&ctlr->queue);
@@ -2199,7 +2210,7 @@ int spi_register_controller(struct spi_controller *ctlr)
	spin_lock_init(&ctlr->bus_lock_spinlock);
	mutex_init(&ctlr->bus_lock_mutex);
	mutex_init(&ctlr->io_mutex);
	mutex_init(&ctlr->add_lock);
	mutex_init(ctlr->dev.add_lock);
	ctlr->bus_lock_flag = 0;
	init_completion(&ctlr->xfer_completion);
	if (!ctlr->max_dma_len)
@@ -2251,7 +2262,10 @@ int spi_register_controller(struct spi_controller *ctlr)
	/* Register devices from the device tree and ACPI */
	of_register_spi_devices(ctlr);
	acpi_register_spi_devices(ctlr);
	return status;

done:
	kfree(ctlr->dev.add_lock);
	return status;
}
EXPORT_SYMBOL_GPL(spi_register_controller);
@@ -2321,7 +2335,7 @@ void spi_unregister_controller(struct spi_controller *ctlr)

	/* Prevent addition of new devices, unregister existing ones */
	if (IS_ENABLED(CONFIG_SPI_DYNAMIC))
		mutex_lock(&ctlr->add_lock);
		mutex_lock(ctlr->dev.add_lock);

	device_for_each_child(&ctlr->dev, NULL, __unregister);

@@ -2345,7 +2359,9 @@ void spi_unregister_controller(struct spi_controller *ctlr)
	mutex_unlock(&board_lock);

	if (IS_ENABLED(CONFIG_SPI_DYNAMIC))
		mutex_unlock(&ctlr->add_lock);
		mutex_unlock(ctlr->dev.add_lock);

	kfree(ctlr->dev.add_lock);
}
EXPORT_SYMBOL_GPL(spi_unregister_controller);

+12 −0
Original line number Diff line number Diff line
@@ -1078,7 +1078,19 @@ struct device {
#else
	KABI_RESERVE(1)
#endif
#ifdef CONFIG_SPI_MASTER
#ifndef __GENKSYMS__
	/*
	 * Reserved for struct spi_controller.
	 * Used to avoid adding the same CS twice.
	 */
	struct mutex *add_lock;
#else
	KABI_RESERVE(2)
#endif
#else
	KABI_RESERVE(2)
#endif
	KABI_RESERVE(3)
	KABI_RESERVE(4)
	KABI_RESERVE(5)
+0 −3
Original line number Diff line number Diff line
@@ -463,9 +463,6 @@ struct spi_controller {
	/* I/O mutex */
	struct mutex		io_mutex;

	/* Used to avoid adding the same CS twice */
	struct mutex		add_lock;

	/* lock and mutex for SPI bus locking */
	spinlock_t		bus_lock_spinlock;
	struct mutex		bus_lock_mutex;