[V2] soc/tegra: fuse: fix illegal free of IO base address

Message ID 1546185488-2317-1-git-send-email-talho@nvidia.com
State Accepted
Headers show
Series
  • [V2] soc/tegra: fuse: fix illegal free of IO base address
Related show

Commit Message

Timo Alho Dec. 30, 2018, 3:58 p.m.
On cases where device tree entries for fuse and clock provider are in
different order, fuse driver needs to defer probing. This leads to
freeing incorrect IO base address as the fuse->base variable gets
overwritten once during first probe invocation. This leads to
following spew during boot:

[    3.082285] Trying to vfree() nonexistent vm area (00000000cfe8fd94)
[    3.082308] WARNING: CPU: 5 PID: 126 at /hdd/l4t/kernel/stable/mm/vmalloc.c:1511 __vunmap+0xcc/0xd8
[    3.082318] Modules linked in:
[    3.082330] CPU: 5 PID: 126 Comm: kworker/5:1 Tainted: G S                4.19.7-tegra-gce119d3 #1
[    3.082340] Hardware name: quill (DT)
[    3.082353] Workqueue: events deferred_probe_work_func
[    3.082364] pstate: 40000005 (nZcv daif -PAN -UAO)
[    3.082372] pc : __vunmap+0xcc/0xd8
[    3.082379] lr : __vunmap+0xcc/0xd8
[    3.082385] sp : ffff00000a1d3b60
[    3.082391] x29: ffff00000a1d3b60 x28: 0000000000000000
[    3.082402] x27: 0000000000000000 x26: ffff000008e8b610
[    3.082413] x25: 0000000000000000 x24: 0000000000000009
[    3.082423] x23: ffff000009221a90 x22: ffff000009f6d000
[    3.082432] x21: 0000000000000000 x20: 0000000000000000
[    3.082442] x19: ffff000009f6d000 x18: ffffffffffffffff
[    3.082452] x17: 0000000000000000 x16: 0000000000000000
[    3.082462] x15: ffff0000091396c8 x14: 0720072007200720
[    3.082471] x13: 0720072007200720 x12: 0720072907340739
[    3.082481] x11: 0764076607380765 x10: 0766076307300730
[    3.082491] x9 : 0730073007300730 x8 : 0730073007280720
[    3.082501] x7 : 0761076507720761 x6 : 0000000000000102
[    3.082510] x5 : 0000000000000000 x4 : 0000000000000000
[    3.082519] x3 : ffffffffffffffff x2 : ffff000009150ff8
[    3.082528] x1 : 3d95b1429fff5200 x0 : 0000000000000000
[    3.082538] Call trace:
[    3.082545]  __vunmap+0xcc/0xd8
[    3.082552]  vunmap+0x24/0x30
[    3.082561]  __iounmap+0x2c/0x38
[    3.082569]  tegra_fuse_probe+0xc8/0x118
[    3.082577]  platform_drv_probe+0x50/0xa0
[    3.082585]  really_probe+0x1b0/0x288
[    3.082593]  driver_probe_device+0x58/0x100
[    3.082601]  __device_attach_driver+0x98/0xf0
[    3.082609]  bus_for_each_drv+0x64/0xc8
[    3.082616]  __device_attach+0xd8/0x130
[    3.082624]  device_initial_probe+0x10/0x18
[    3.082631]  bus_probe_device+0x90/0x98
[    3.082638]  deferred_probe_work_func+0x74/0xb0
[    3.082649]  process_one_work+0x1e0/0x318
[    3.082656]  worker_thread+0x228/0x450
[    3.082664]  kthread+0x128/0x130
[    3.082672]  ret_from_fork+0x10/0x18
[    3.082678] ---[ end trace 0810fe6ba772c1c7 ]---

Fix this by retaining the value of fuse->base until driver has
successfully probed.

Signed-off-by: Timo Alho <talho@nvidia.com>
---
V2: Addressed review comments from Jon. Which means essentially a rewrote of the patch.
---
 drivers/soc/tegra/fuse/fuse-tegra.c | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

Comments

Peter De Schrijver Jan. 2, 2019, 11:27 a.m. | #1
On Sun, Dec 30, 2018 at 05:58:08PM +0200, Timo Alho wrote:
> On cases where device tree entries for fuse and clock provider are in
> different order, fuse driver needs to defer probing. This leads to
> freeing incorrect IO base address as the fuse->base variable gets
> overwritten once during first probe invocation. This leads to
> following spew during boot:
> 
..
> 
> Fix this by retaining the value of fuse->base until driver has
> successfully probed.
> 

Maybe there should be a comment in the code on why this is needed
because it's not obvious to understand by just reading the code I think.

Peter.

> Signed-off-by: Timo Alho <talho@nvidia.com>
> ---
> V2: Addressed review comments from Jon. Which means essentially a rewrote of the patch.
> ---
>  drivers/soc/tegra/fuse/fuse-tegra.c | 12 +++++++++---
>  1 file changed, 9 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/soc/tegra/fuse/fuse-tegra.c b/drivers/soc/tegra/fuse/fuse-tegra.c
> index a33ee8e..5162570 100644
> --- a/drivers/soc/tegra/fuse/fuse-tegra.c
> +++ b/drivers/soc/tegra/fuse/fuse-tegra.c
> @@ -137,13 +137,17 @@ static int tegra_fuse_probe(struct platform_device *pdev)
>  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>  	fuse->phys = res->start;
>  	fuse->base = devm_ioremap_resource(&pdev->dev, res);
> -	if (IS_ERR(fuse->base))
> -		return PTR_ERR(fuse->base);
> +	if (IS_ERR(fuse->base)) {
> +		err = PTR_ERR(fuse->base);
> +		fuse->base = base;
> +		return err;
> +	}
>  
>  	fuse->clk = devm_clk_get(&pdev->dev, "fuse");
>  	if (IS_ERR(fuse->clk)) {
>  		dev_err(&pdev->dev, "failed to get FUSE clock: %ld",
>  			PTR_ERR(fuse->clk));
> +		fuse->base = base;
>  		return PTR_ERR(fuse->clk);
>  	}
>  
> @@ -152,8 +156,10 @@ static int tegra_fuse_probe(struct platform_device *pdev)
>  
>  	if (fuse->soc->probe) {
>  		err = fuse->soc->probe(fuse);
> -		if (err < 0)
> +		if (err < 0) {
> +			fuse->base = base;
>  			return err;
> +		}
>  	}
>  
>  	if (tegra_fuse_create_sysfs(&pdev->dev, fuse->soc->info->size,
> -- 
> 2.7.4
>
Jon Hunter Jan. 2, 2019, 11:31 a.m. | #2
On 30/12/2018 15:58, Timo Alho wrote:
> On cases where device tree entries for fuse and clock provider are in
> different order, fuse driver needs to defer probing. This leads to
> freeing incorrect IO base address as the fuse->base variable gets
> overwritten once during first probe invocation. This leads to
> following spew during boot:
> 
> [    3.082285] Trying to vfree() nonexistent vm area (00000000cfe8fd94)
> [    3.082308] WARNING: CPU: 5 PID: 126 at /hdd/l4t/kernel/stable/mm/vmalloc.c:1511 __vunmap+0xcc/0xd8
> [    3.082318] Modules linked in:
> [    3.082330] CPU: 5 PID: 126 Comm: kworker/5:1 Tainted: G S                4.19.7-tegra-gce119d3 #1
> [    3.082340] Hardware name: quill (DT)
> [    3.082353] Workqueue: events deferred_probe_work_func
> [    3.082364] pstate: 40000005 (nZcv daif -PAN -UAO)
> [    3.082372] pc : __vunmap+0xcc/0xd8
> [    3.082379] lr : __vunmap+0xcc/0xd8
> [    3.082385] sp : ffff00000a1d3b60
> [    3.082391] x29: ffff00000a1d3b60 x28: 0000000000000000
> [    3.082402] x27: 0000000000000000 x26: ffff000008e8b610
> [    3.082413] x25: 0000000000000000 x24: 0000000000000009
> [    3.082423] x23: ffff000009221a90 x22: ffff000009f6d000
> [    3.082432] x21: 0000000000000000 x20: 0000000000000000
> [    3.082442] x19: ffff000009f6d000 x18: ffffffffffffffff
> [    3.082452] x17: 0000000000000000 x16: 0000000000000000
> [    3.082462] x15: ffff0000091396c8 x14: 0720072007200720
> [    3.082471] x13: 0720072007200720 x12: 0720072907340739
> [    3.082481] x11: 0764076607380765 x10: 0766076307300730
> [    3.082491] x9 : 0730073007300730 x8 : 0730073007280720
> [    3.082501] x7 : 0761076507720761 x6 : 0000000000000102
> [    3.082510] x5 : 0000000000000000 x4 : 0000000000000000
> [    3.082519] x3 : ffffffffffffffff x2 : ffff000009150ff8
> [    3.082528] x1 : 3d95b1429fff5200 x0 : 0000000000000000
> [    3.082538] Call trace:
> [    3.082545]  __vunmap+0xcc/0xd8
> [    3.082552]  vunmap+0x24/0x30
> [    3.082561]  __iounmap+0x2c/0x38
> [    3.082569]  tegra_fuse_probe+0xc8/0x118
> [    3.082577]  platform_drv_probe+0x50/0xa0
> [    3.082585]  really_probe+0x1b0/0x288
> [    3.082593]  driver_probe_device+0x58/0x100
> [    3.082601]  __device_attach_driver+0x98/0xf0
> [    3.082609]  bus_for_each_drv+0x64/0xc8
> [    3.082616]  __device_attach+0xd8/0x130
> [    3.082624]  device_initial_probe+0x10/0x18
> [    3.082631]  bus_probe_device+0x90/0x98
> [    3.082638]  deferred_probe_work_func+0x74/0xb0
> [    3.082649]  process_one_work+0x1e0/0x318
> [    3.082656]  worker_thread+0x228/0x450
> [    3.082664]  kthread+0x128/0x130
> [    3.082672]  ret_from_fork+0x10/0x18
> [    3.082678] ---[ end trace 0810fe6ba772c1c7 ]---
> 
> Fix this by retaining the value of fuse->base until driver has
> successfully probed.
> 
> Signed-off-by: Timo Alho <talho@nvidia.com>
> ---
> V2: Addressed review comments from Jon. Which means essentially a rewrote of the patch.
> ---
>  drivers/soc/tegra/fuse/fuse-tegra.c | 12 +++++++++---
>  1 file changed, 9 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/soc/tegra/fuse/fuse-tegra.c b/drivers/soc/tegra/fuse/fuse-tegra.c
> index a33ee8e..5162570 100644
> --- a/drivers/soc/tegra/fuse/fuse-tegra.c
> +++ b/drivers/soc/tegra/fuse/fuse-tegra.c
> @@ -137,13 +137,17 @@ static int tegra_fuse_probe(struct platform_device *pdev)
>  	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
>  	fuse->phys = res->start;
>  	fuse->base = devm_ioremap_resource(&pdev->dev, res);
> -	if (IS_ERR(fuse->base))
> -		return PTR_ERR(fuse->base);
> +	if (IS_ERR(fuse->base)) {
> +		err = PTR_ERR(fuse->base);
> +		fuse->base = base;
> +		return err;
> +	}
>  
>  	fuse->clk = devm_clk_get(&pdev->dev, "fuse");
>  	if (IS_ERR(fuse->clk)) {
>  		dev_err(&pdev->dev, "failed to get FUSE clock: %ld",
>  			PTR_ERR(fuse->clk));
> +		fuse->base = base;
>  		return PTR_ERR(fuse->clk);
>  	}
>  
> @@ -152,8 +156,10 @@ static int tegra_fuse_probe(struct platform_device *pdev)
>  
>  	if (fuse->soc->probe) {
>  		err = fuse->soc->probe(fuse);
> -		if (err < 0)
> +		if (err < 0) {
> +			fuse->base = base;
>  			return err;
> +		}
>  	}
>  
>  	if (tegra_fuse_create_sysfs(&pdev->dev, fuse->soc->info->size,
> 

Acked-by: Jon Hunter <jonathanh@nvidia.com>

Cheers
Jon

Patch

diff --git a/drivers/soc/tegra/fuse/fuse-tegra.c b/drivers/soc/tegra/fuse/fuse-tegra.c
index a33ee8e..5162570 100644
--- a/drivers/soc/tegra/fuse/fuse-tegra.c
+++ b/drivers/soc/tegra/fuse/fuse-tegra.c
@@ -137,13 +137,17 @@  static int tegra_fuse_probe(struct platform_device *pdev)
 	res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
 	fuse->phys = res->start;
 	fuse->base = devm_ioremap_resource(&pdev->dev, res);
-	if (IS_ERR(fuse->base))
-		return PTR_ERR(fuse->base);
+	if (IS_ERR(fuse->base)) {
+		err = PTR_ERR(fuse->base);
+		fuse->base = base;
+		return err;
+	}
 
 	fuse->clk = devm_clk_get(&pdev->dev, "fuse");
 	if (IS_ERR(fuse->clk)) {
 		dev_err(&pdev->dev, "failed to get FUSE clock: %ld",
 			PTR_ERR(fuse->clk));
+		fuse->base = base;
 		return PTR_ERR(fuse->clk);
 	}
 
@@ -152,8 +156,10 @@  static int tegra_fuse_probe(struct platform_device *pdev)
 
 	if (fuse->soc->probe) {
 		err = fuse->soc->probe(fuse);
-		if (err < 0)
+		if (err < 0) {
+			fuse->base = base;
 			return err;
+		}
 	}
 
 	if (tegra_fuse_create_sysfs(&pdev->dev, fuse->soc->info->size,