diff mbox

dma: mv_xor: fix kernel crash on probe error

Message ID 20131212235908.GZ4360@n2100.arm.linux.org.uk (mailing list archive)
State New, archived
Headers show

Commit Message

Russell King - ARM Linux Dec. 12, 2013, 11:59 p.m. UTC
From: Russell King <rmk+kernel@arm.linux.org.uk>
Subject: [PATCH] dmaengine: mv_xor: fix oops when channels fail to initialise

When a channel fails to initialise, we error out and clean up any
previously unregistered channels by walking the entire xordev->channels
array.  Unfortunately, there are paths which end up storing an error
pointer in this array, which we then try and dereference in the cleanup
code, which causes an oops.

Fix this by avoiding writing invalid pointers to this array in the first
place.

Tested-by: Aaro Koskinen <aaro.koskinen@iki.fi>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
---
 drivers/dma/mv_xor.c |   24 +++++++++++++-----------
 1 files changed, 13 insertions(+), 11 deletions(-)

Comments

Vinod Koul Dec. 18, 2013, 4:35 p.m. UTC | #1
On Thu, Dec 12, 2013 at 11:59:08PM +0000, Russell King - ARM Linux wrote:
> From: Russell King <rmk+kernel@arm.linux.org.uk>
> Subject: [PATCH] dmaengine: mv_xor: fix oops when channels fail to initialise
> 
> When a channel fails to initialise, we error out and clean up any
> previously unregistered channels by walking the entire xordev->channels
> array.  Unfortunately, there are paths which end up storing an error
> pointer in this array, which we then try and dereference in the cleanup
> code, which causes an oops.
> 
> Fix this by avoiding writing invalid pointers to this array in the first
> place.
> 
> Tested-by: Aaro Koskinen <aaro.koskinen@iki.fi>
> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Acked-by: Vinod Koul <vinod.koul@intel.com>

--
~Vinod
> ---
>  drivers/dma/mv_xor.c |   24 +++++++++++++-----------
>  1 files changed, 13 insertions(+), 11 deletions(-)
> 
> diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c
> index 7807f0ef4e20..a7e91090443e 100644
> --- a/drivers/dma/mv_xor.c
> +++ b/drivers/dma/mv_xor.c
> @@ -1176,6 +1176,7 @@ static int mv_xor_probe(struct platform_device *pdev)
>  		int i = 0;
>  
>  		for_each_child_of_node(pdev->dev.of_node, np) {
> +			struct mv_xor_chan *chan;
>  			dma_cap_mask_t cap_mask;
>  			int irq;
>  
> @@ -1193,21 +1194,21 @@ static int mv_xor_probe(struct platform_device *pdev)
>  				goto err_channel_add;
>  			}
>  
> -			xordev->channels[i] =
> -				mv_xor_channel_add(xordev, pdev, i,
> -						   cap_mask, irq);
> -			if (IS_ERR(xordev->channels[i])) {
> -				ret = PTR_ERR(xordev->channels[i]);
> -				xordev->channels[i] = NULL;
> +			chan = mv_xor_channel_add(xordev, pdev, i,
> +						  cap_mask, irq);
> +			if (IS_ERR(chan)) {
> +				ret = PTR_ERR(chan);
>  				irq_dispose_mapping(irq);
>  				goto err_channel_add;
>  			}
>  
> +			xordev->channels[i] = chan;
>  			i++;
>  		}
>  	} else if (pdata && pdata->channels) {
>  		for (i = 0; i < MV_XOR_MAX_CHANNELS; i++) {
>  			struct mv_xor_channel_data *cd;
> +			struct mv_xor_chan *chan;
>  			int irq;
>  
>  			cd = &pdata->channels[i];
> @@ -1222,13 +1223,14 @@ static int mv_xor_probe(struct platform_device *pdev)
>  				goto err_channel_add;
>  			}
>  
> -			xordev->channels[i] =
> -				mv_xor_channel_add(xordev, pdev, i,
> -						   cd->cap_mask, irq);
> -			if (IS_ERR(xordev->channels[i])) {
> -				ret = PTR_ERR(xordev->channels[i]);
> +			chan = mv_xor_channel_add(xordev, pdev, i,
> +						  cd->cap_mask, irq);
> +			if (IS_ERR(chan)) {
> +				ret = PTR_ERR(chan);
>  				goto err_channel_add;
>  			}
> +
> +			xordev->channels[i] = chan;
>  		}
>  	}
>
diff mbox

Patch

diff --git a/drivers/dma/mv_xor.c b/drivers/dma/mv_xor.c
index 7807f0ef4e20..a7e91090443e 100644
--- a/drivers/dma/mv_xor.c
+++ b/drivers/dma/mv_xor.c
@@ -1176,6 +1176,7 @@  static int mv_xor_probe(struct platform_device *pdev)
 		int i = 0;
 
 		for_each_child_of_node(pdev->dev.of_node, np) {
+			struct mv_xor_chan *chan;
 			dma_cap_mask_t cap_mask;
 			int irq;
 
@@ -1193,21 +1194,21 @@  static int mv_xor_probe(struct platform_device *pdev)
 				goto err_channel_add;
 			}
 
-			xordev->channels[i] =
-				mv_xor_channel_add(xordev, pdev, i,
-						   cap_mask, irq);
-			if (IS_ERR(xordev->channels[i])) {
-				ret = PTR_ERR(xordev->channels[i]);
-				xordev->channels[i] = NULL;
+			chan = mv_xor_channel_add(xordev, pdev, i,
+						  cap_mask, irq);
+			if (IS_ERR(chan)) {
+				ret = PTR_ERR(chan);
 				irq_dispose_mapping(irq);
 				goto err_channel_add;
 			}
 
+			xordev->channels[i] = chan;
 			i++;
 		}
 	} else if (pdata && pdata->channels) {
 		for (i = 0; i < MV_XOR_MAX_CHANNELS; i++) {
 			struct mv_xor_channel_data *cd;
+			struct mv_xor_chan *chan;
 			int irq;
 
 			cd = &pdata->channels[i];
@@ -1222,13 +1223,14 @@  static int mv_xor_probe(struct platform_device *pdev)
 				goto err_channel_add;
 			}
 
-			xordev->channels[i] =
-				mv_xor_channel_add(xordev, pdev, i,
-						   cd->cap_mask, irq);
-			if (IS_ERR(xordev->channels[i])) {
-				ret = PTR_ERR(xordev->channels[i]);
+			chan = mv_xor_channel_add(xordev, pdev, i,
+						  cd->cap_mask, irq);
+			if (IS_ERR(chan)) {
+				ret = PTR_ERR(chan);
 				goto err_channel_add;
 			}
+
+			xordev->channels[i] = chan;
 		}
 	}