Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

extcon: extcon-max14577: Fix potential work-queue cancellation race

The extcon IRQ schedules a work item. IRQ is requested using devm while
WQ is cancelld at remove(). This mixing of devm and manual unwinding has
potential case where the WQ has been emptied (.remove() was ran) but
devm unwinding of IRQ was not yet done. It is possible the IRQ is triggered
at this point scheduling new work item to the already flushed queue.

Use new devm_work_autocancel() to remove the remove() and to kill the bug.

Signed-off-by: Matti Vaittinen <matti.vaittinen@fi.rohmeurope.com>
Reviewed-by: Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
Reviewed-by: Hans de Goede <hdegoede@redhat.com>
Acked-by: Chanwoo Choi <cw00.choi@samsung.com>
Link: https://lore.kernel.org/r/ee8545f59ae3a93f0a70f640ecbd7e31cfadbcb9.1623146580.git.matti.vaittinen@fi.rohmeurope.com
Signed-off-by: Hans de Goede <hdegoede@redhat.com>

authored by

Matti Vaittinen and committed by
Hans de Goede
14ad7682 7a2c4cc5

+5 -11
+5 -11
drivers/extcon/extcon-max14577.c
··· 6 6 // Chanwoo Choi <cw00.choi@samsung.com> 7 7 // Krzysztof Kozlowski <krzk@kernel.org> 8 8 9 + #include <linux/devm-helpers.h> 9 10 #include <linux/kernel.h> 10 11 #include <linux/module.h> 11 12 #include <linux/i2c.h> ··· 674 673 platform_set_drvdata(pdev, info); 675 674 mutex_init(&info->mutex); 676 675 677 - INIT_WORK(&info->irq_work, max14577_muic_irq_work); 676 + ret = devm_work_autocancel(&pdev->dev, &info->irq_work, 677 + max14577_muic_irq_work); 678 + if (ret) 679 + return ret; 678 680 679 681 switch (max14577->dev_type) { 680 682 case MAXIM_DEVICE_TYPE_MAX77836: ··· 770 766 return ret; 771 767 } 772 768 773 - static int max14577_muic_remove(struct platform_device *pdev) 774 - { 775 - struct max14577_muic_info *info = platform_get_drvdata(pdev); 776 - 777 - cancel_work_sync(&info->irq_work); 778 - 779 - return 0; 780 - } 781 - 782 769 static const struct platform_device_id max14577_muic_id[] = { 783 770 { "max14577-muic", MAXIM_DEVICE_TYPE_MAX14577, }, 784 771 { "max77836-muic", MAXIM_DEVICE_TYPE_MAX77836, }, ··· 792 797 .of_match_table = of_max14577_muic_dt_match, 793 798 }, 794 799 .probe = max14577_muic_probe, 795 - .remove = max14577_muic_remove, 796 800 .id_table = max14577_muic_id, 797 801 }; 798 802