Commit b84923cc 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 db2d81fa
Loading
Loading
Loading
Loading
+26 −11
Original line number Diff line number Diff line
@@ -575,7 +575,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) {
@@ -619,7 +619,7 @@ int spi_add_device(struct spi_device *spi)
	}

done:
	mutex_unlock(&ctlr->add_lock);
	mutex_unlock(ctlr->dev.add_lock);
	return status;
}
EXPORT_SYMBOL_GPL(spi_add_device);
@@ -2682,14 +2682,20 @@ int spi_register_controller(struct spi_controller *ctlr)
	if (status)
		return status;

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

	if (ctlr->bus_num >= 0) {
		/* devices with a fixed bus num must check-in with the num */
		mutex_lock(&board_lock);
		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 free_add_lock;
		}
		ctlr->bus_num = id;
	} else if (ctlr->dev.of_node) {
		/* allocate dynamic bus number using Linux idr */
@@ -2700,8 +2706,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 free_add_lock;
			}
		}
	}
	if (ctlr->bus_num < 0) {
@@ -2715,8 +2723,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 free_add_lock;
		}

		ctlr->bus_num = id;
	}
	INIT_LIST_HEAD(&ctlr->queue);
@@ -2724,7 +2735,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)
@@ -2801,6 +2812,8 @@ int spi_register_controller(struct spi_controller *ctlr)
	mutex_lock(&board_lock);
	idr_remove(&spi_master_idr, ctlr->bus_num);
	mutex_unlock(&board_lock);
free_add_lock:
	kfree(ctlr->dev.add_lock);
	return status;
}
EXPORT_SYMBOL_GPL(spi_register_controller);
@@ -2870,7 +2883,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);

@@ -2895,7 +2908,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);

	/* Release the last reference on the controller if its driver
	 * has not yet been converted to devm_spi_alloc_master/slave().
+8 −0
Original line number Diff line number Diff line
@@ -567,7 +567,15 @@ struct device {
	bool			dma_ops_bypass : 1;
#endif
	/* Use device_extended after all RESERVE fields used */
#ifdef CONFIG_SPI_MASTER
	/*
	 * Reserved for struct spi_controller.
	 * Used to avoid adding the same CS twice.
	 */
	KABI_USE(1, struct mutex *add_lock)
#else
	KABI_RESERVE(1)
#endif
	KABI_RESERVE(2)
	KABI_RESERVE(3)
	KABI_RESERVE(4)
+0 −3
Original line number Diff line number Diff line
@@ -527,9 +527,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;