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

hwmon: Fix a potential race condition on unload

Fix a potential race condition when some hardware monitoring platform
drivers are being unloaded. I believe that the driver data pointer
shouldn't be cleared before all the sysfs files are removed, otherwise
a sysfs callback might attempt to dereference a NULL pointer. I'm not
sure exactly what the driver core protects drivers against, so let's
play it safe.

While we're here, clear the driver data pointer when probe fails, so
as to not leave an invalid pointer behind us.

Signed-off-by: Jean Delvare <khali@linux-fr.org>
Signed-off-by: Mark M. Hoffman <mhoffman@lightlink.com>

authored by

Jean Delvare and committed by
Mark M. Hoffman
04a6217d ec5e1a4b

+9 -5
+2 -1
drivers/hwmon/abituguru.c
··· 1287 1287 for (i = 0; i < ARRAY_SIZE(abituguru_sysfs_attr); i++) 1288 1288 device_remove_file(&pdev->dev, 1289 1289 &abituguru_sysfs_attr[i].dev_attr); 1290 + platform_set_drvdata(pdev, NULL); 1290 1291 kfree(data); 1291 1292 return res; 1292 1293 } ··· 1297 1296 int i; 1298 1297 struct abituguru_data *data = platform_get_drvdata(pdev); 1299 1298 1300 - platform_set_drvdata(pdev, NULL); 1301 1299 hwmon_device_unregister(data->class_dev); 1302 1300 for (i = 0; data->sysfs_attr[i].dev_attr.attr.name; i++) 1303 1301 device_remove_file(&pdev->dev, &data->sysfs_attr[i].dev_attr); 1304 1302 for (i = 0; i < ARRAY_SIZE(abituguru_sysfs_attr); i++) 1305 1303 device_remove_file(&pdev->dev, 1306 1304 &abituguru_sysfs_attr[i].dev_attr); 1305 + platform_set_drvdata(pdev, NULL); 1307 1306 kfree(data); 1308 1307 1309 1308 return 0;
+1 -1
drivers/hwmon/f71805f.c
··· 1242 1242 struct resource *res; 1243 1243 int i; 1244 1244 1245 - platform_set_drvdata(pdev, NULL); 1246 1245 hwmon_device_unregister(data->class_dev); 1247 1246 sysfs_remove_group(&pdev->dev.kobj, &f71805f_group); 1248 1247 for (i = 0; i < 4; i++) 1249 1248 sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_optin[i]); 1250 1249 sysfs_remove_group(&pdev->dev.kobj, &f71805f_group_pwm_freq); 1250 + platform_set_drvdata(pdev, NULL); 1251 1251 kfree(data); 1252 1252 1253 1253 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+1 -1
drivers/hwmon/pc87427.c
··· 484 484 struct resource *res; 485 485 int i; 486 486 487 - platform_set_drvdata(pdev, NULL); 488 487 hwmon_device_unregister(data->class_dev); 489 488 device_remove_file(&pdev->dev, &dev_attr_name); 490 489 for (i = 0; i < 8; i++) { ··· 491 492 continue; 492 493 sysfs_remove_group(&pdev->dev.kobj, &pc87427_group_fan[i]); 493 494 } 495 + platform_set_drvdata(pdev, NULL); 494 496 kfree(data); 495 497 496 498 res = platform_get_resource(pdev, IORESOURCE_IO, 0);
+2 -1
drivers/hwmon/smsc47m1.c
··· 597 597 error_remove_files: 598 598 sysfs_remove_group(&dev->kobj, &smsc47m1_group); 599 599 error_free: 600 + platform_set_drvdata(pdev, NULL); 600 601 kfree(data); 601 602 error_release: 602 603 release_region(res->start, SMSC_EXTENT); ··· 609 608 struct smsc47m1_data *data = platform_get_drvdata(pdev); 610 609 struct resource *res; 611 610 612 - platform_set_drvdata(pdev, NULL); 613 611 hwmon_device_unregister(data->class_dev); 614 612 sysfs_remove_group(&pdev->dev.kobj, &smsc47m1_group); 615 613 616 614 res = platform_get_resource(pdev, IORESOURCE_IO, 0); 617 615 release_region(res->start, SMSC_EXTENT); 616 + platform_set_drvdata(pdev, NULL); 618 617 kfree(data); 619 618 620 619 return 0;
+1
drivers/hwmon/vt8231.c
··· 743 743 sysfs_remove_group(&pdev->dev.kobj, &vt8231_group); 744 744 745 745 exit_free: 746 + platform_set_drvdata(pdev, NULL); 746 747 kfree(data); 747 748 748 749 exit_release:
+2 -1
drivers/hwmon/w83627hf.c
··· 1306 1306 sysfs_remove_group(&dev->kobj, &w83627hf_group); 1307 1307 sysfs_remove_group(&dev->kobj, &w83627hf_group_opt); 1308 1308 ERROR3: 1309 + platform_set_drvdata(pdev, NULL); 1309 1310 kfree(data); 1310 1311 ERROR1: 1311 1312 release_region(res->start, WINB_REGION_SIZE); ··· 1319 1318 struct w83627hf_data *data = platform_get_drvdata(pdev); 1320 1319 struct resource *res; 1321 1320 1322 - platform_set_drvdata(pdev, NULL); 1323 1321 hwmon_device_unregister(data->class_dev); 1324 1322 1325 1323 sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group); 1326 1324 sysfs_remove_group(&pdev->dev.kobj, &w83627hf_group_opt); 1325 + platform_set_drvdata(pdev, NULL); 1327 1326 kfree(data); 1328 1327 1329 1328 res = platform_get_resource(pdev, IORESOURCE_IO, 0);