diff mbox series

[3/6] bus: fsl-mc: fix double free of the root DPRC fsl-mc device

Message ID 20220208145928.12468-4-laurentiu.tudor@nxp.com (mailing list archive)
State New, archived
Headers show
Series bus: fsl-mc: fixes and .shutdown() op for dprc driver | expand

Commit Message

Laurentiu Tudor Feb. 8, 2022, 2:59 p.m. UTC
From: Laurentiu Tudor <laurentiu.tudor@nxp.com>

By simply calling remove() op from shutdown() op we end up
deleting twice the root DPRC fsl-mc device. This causes various
issues such as the crash below [1], on reboot. Re-arrange the code
in shutdown and remove callbacks so this does not happen any more.

Unable to handle kernel NULL pointer dereference at virtual address 0
Mem abort info:
  ESR = 0x96000006
  EC = 0x25: DABT (current EL), IL = 32 bits
  SET = 0, FnV = 0
  EA = 0, S1PTW = 0
  FSC = 0x06: level 2 translation fault
Data abort info:
  ISV = 0, ISS = 0x00000006
  CM = 0, WnR = 0
user pgtable: 4k pages, 48-bit VAs, pgdp=00000081086db000
Internal error: Oops: 96000006 [#1] PREEMPT SMP
Modules linked in:
CPU: 1 PID: 977 Comm: reboot Not tainted 5.14.0-rc1-00221
Hardware name: Freescale Layerscape 2088A RDB Board (DT)
pstate: 60000005 (nZCv daif -PAN -UAO -TCO BTYPE=--)
pc : sysfs_remove_link_from_group+0x28/0x94
lr : iommu_device_unlink+0x94/0xb4
sp : ffff800012b3b8c0
x29: ffff800012b3b8c0 x28: ffff24f8e061a940 x27: 0000000000000000
x26: 0000000000000000 x25: ffffb43783811228 x24: ffff24f840a882f0
x23: ffff24f8400cf000 x22: 0000000000000003 x21: ffffb43783bb6e10
x20: ffff24f8c9641040 x19: 0000000000000000 x18: ffffffffffffffff
x17: 3236366535672d31 x16: 323230302d316372 x15: ffff800092b3b537
x14: 0000000000000004 x13: 0000000000000000 x12: ffff24f840467af8
x11: ffff24f8404c7d98 x10: ffff24f840467908 x9 : ffff24f840064b98
x8 : ffff24f840467930 x7 : ffff24f8e061a940 x6 : ffff24f840453b30
x5 : 0000000000000001 x4 : 0000000000000000 x3 : ffffb43784442d28
x2 : ffff24f8c9641040 x1 : ffffb43783bb6e10 x0 : 0000000000000000
Call trace:
 sysfs_remove_link_from_group+0x28/0x94
 iommu_device_unlink+0x94/0xb4
 iommu_release_device+0x34/0x94
 iommu_bus_notifier+0xc0/0xd4
 blocking_notifier_call_chain+0x70/0xac
 device_del+0x2f4/0x424
 fsl_mc_device_remove+0x4c/0x80
 __fsl_mc_device_remove+0x14/0x2c
 device_for_each_child+0x5c/0xac
 dprc_remove+0x44/0x70
 fsl_mc_driver_remove+0x4c/0xa0
 __device_release_driver+0x188/0x22c
 device_release_driver+0x30/0x50
 bus_remove_device+0x10c/0x140
 device_del+0x16c/0x424
 fsl_mc_bus_remove+0xb8/0x160
 fsl_mc_bus_shutdown+0x14/0x20
 platform_shutdown+0x28/0x40
 device_shutdown+0x15c/0x360
 __do_sys_reboot+0x218/0x2a0
 __arm64_sys_reboot+0x28/0x34
 invoke_syscall+0x48/0x114
 el0_svc_common+0x40/0xdc
 do_el0_svc+0x2c/0x94
 el0_svc+0x2c/0x54
 el0t_64_sync_handler+0xa8/0x12c
 el0t_64_sync+0x198/0x19c
Code: aa0203f4 f90013f5 aa0103f5 b5000060 (f9400002)
---[ end trace 1a98489358f432bb ]---
/etc/rc6.d/S90reboot: line 15:   977 Segmentation fault      reboot -d -f

Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com>
---
 drivers/bus/fsl-mc/fsl-mc-bus.c | 30 +++++++++++++++++++-----------
 1 file changed, 19 insertions(+), 11 deletions(-)
diff mbox series

Patch

diff --git a/drivers/bus/fsl-mc/fsl-mc-bus.c b/drivers/bus/fsl-mc/fsl-mc-bus.c
index 8cbac1b4b60e..459947988e0d 100644
--- a/drivers/bus/fsl-mc/fsl-mc-bus.c
+++ b/drivers/bus/fsl-mc/fsl-mc-bus.c
@@ -1230,21 +1230,18 @@  static int fsl_mc_bus_probe(struct platform_device *pdev)
 }
 
 /*
- * fsl_mc_bus_remove - callback invoked when the root MC bus is being
- * removed
+ * fsl_mc_bus_shutdown - callback invoked when the root MC bus is being
+ * shutdown
  */
-static int fsl_mc_bus_remove(struct platform_device *pdev)
+static void fsl_mc_bus_shutdown(struct platform_device *pdev)
 {
 	struct fsl_mc *mc = platform_get_drvdata(pdev);
 	struct fsl_mc_io *mc_io;
 
 	if (!fsl_mc_is_root_dprc(&mc->root_mc_bus_dev->dev))
-		return -EINVAL;
+		return;
 
 	mc_io = mc->root_mc_bus_dev->mc_io;
-
-	fsl_mc_device_remove(mc->root_mc_bus_dev);
-
 	fsl_destroy_mc_io(mc_io);
 
 	bus_unregister_notifier(&fsl_mc_bus_type, &fsl_mc_nb);
@@ -1258,13 +1255,24 @@  static int fsl_mc_bus_remove(struct platform_device *pdev)
 		       (GCR1_P1_STOP | GCR1_P2_STOP),
 		       mc->fsl_mc_regs + FSL_MC_GCR1);
 	}
-
-	return 0;
 }
 
-static void fsl_mc_bus_shutdown(struct platform_device *pdev)
+/*
+ * fsl_mc_bus_remove - callback invoked when the root MC bus is being
+ * removed
+ */
+static int fsl_mc_bus_remove(struct platform_device *pdev)
 {
-	fsl_mc_bus_remove(pdev);
+	struct fsl_mc *mc = platform_get_drvdata(pdev);
+
+	if (!fsl_mc_is_root_dprc(&mc->root_mc_bus_dev->dev))
+		return -EINVAL;
+
+	fsl_mc_device_remove(mc->root_mc_bus_dev);
+
+	fsl_mc_bus_shutdown(pdev);
+
+	return 0;
 }
 
 static const struct of_device_id fsl_mc_bus_match_table[] = {