crypto: talitos - Prevent panic in probe error path
authorAaron Sierra <asierra@xes-inc.com>
Wed, 5 Aug 2015 21:52:08 +0000 (16:52 -0500)
committerHerbert Xu <herbert@gondor.apana.org.au>
Mon, 10 Aug 2015 15:19:05 +0000 (23:19 +0800)
The probe error path for this driver, for all intents and purposes,
is the talitos_remove() function due to the common "goto err_out".

Without this patch applied, talitos_remove() will panic under these
two conditions:

1. If the RNG device hasn't been registered via
   talitos_register_rng() prior to entry into talitos_remove(),
   then the attempt to unregister the RNG "device" will cause a panic.

2. If the priv->chan array has not been allocated prior to entry
   into talitos_remove(), then the per-channel FIFO cleanup will panic
   because of the dereference of that NULL "array".

Both of the above scenarios occur if talitos_probe_irq() fails.

This patch resolves issue #1 by introducing a boolean to mask the
hwrng_unregister() call in talitos_unregister_rng() if RNG device
registration was unsuccessful.

It resolves issue #2 by checking that priv->chan is not NULL in the
per-channel FIFO cleanup for loop.

Signed-off-by: Aaron Sierra <asierra@xes-inc.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
drivers/crypto/talitos.c
drivers/crypto/talitos.h

index 43727c915a59bd36ece6cefe6779b2d037fc9723..1bc8dd91e217592c78afd3a0b35c5c1c264e7a8b 100644 (file)
@@ -766,6 +766,7 @@ static int talitos_rng_init(struct hwrng *rng)
 static int talitos_register_rng(struct device *dev)
 {
        struct talitos_private *priv = dev_get_drvdata(dev);
+       int err;
 
        priv->rng.name          = dev_driver_string(dev),
        priv->rng.init          = talitos_rng_init,
@@ -773,14 +774,22 @@ static int talitos_register_rng(struct device *dev)
        priv->rng.data_read     = talitos_rng_data_read,
        priv->rng.priv          = (unsigned long)dev;
 
-       return hwrng_register(&priv->rng);
+       err = hwrng_register(&priv->rng);
+       if (!err)
+               priv->rng_registered = true;
+
+       return err;
 }
 
 static void talitos_unregister_rng(struct device *dev)
 {
        struct talitos_private *priv = dev_get_drvdata(dev);
 
+       if (!priv->rng_registered)
+               return;
+
        hwrng_unregister(&priv->rng);
+       priv->rng_registered = false;
 }
 
 /*
@@ -2673,7 +2682,7 @@ static int talitos_remove(struct platform_device *ofdev)
        if (hw_supports(dev, DESC_HDR_SEL0_RNG))
                talitos_unregister_rng(dev);
 
-       for (i = 0; i < priv->num_channels; i++)
+       for (i = 0; priv->chan && i < priv->num_channels; i++)
                kfree(priv->chan[i].fifo);
 
        kfree(priv->chan);
index 163cfe733bf055d36e5bbf21591d8571e3a0da96..0090f3211d68bc94af9d4105f51de7c1123ded0b 100644 (file)
@@ -149,6 +149,7 @@ struct talitos_private {
 
        /* hwrng device */
        struct hwrng rng;
+       bool rng_registered;
 };
 
 extern int talitos_submit(struct device *dev, int ch, struct talitos_desc *desc,