crypto: nx - Check for bogus firmware properties
authorHerbert Xu <herbert@gondor.apana.org.au>
Fri, 19 Jun 2015 04:07:54 +0000 (12:07 +0800)
committerHerbert Xu <herbert@gondor.apana.org.au>
Sun, 21 Jun 2015 11:59:21 +0000 (19:59 +0800)
The nx driver reads two crucial paramters from the firmware for
each crypto algorithm, the maximum SG list length and byte limit.
Unfortunately those two parameters may be bogus, or worse they
may be absent altogether.  When this happens the algorithms will
still register successfully but will fail when used or tested.

This patch adds checks to report any firmware entries which are
found to be bogus, and avoid registering algorithms which have
bogus parameters.  A warning is also printed when an algorithm
is not registered because of this as there may have been no firmware
entries for it at all.

Reported-by: Ondrej Moriš <omoris@redhat.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
drivers/crypto/nx/nx.c

index 847350534cc190d5b8bc38941bc9869e884bfe23..f6198f29a4a811b0cbcb2fb5062ece5a5d2bb421 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/scatterlist.h>
 #include <linux/device.h>
 #include <linux/of.h>
+#include <linux/types.h>
 #include <asm/hvcall.h>
 #include <asm/vio.h>
 
@@ -398,6 +399,13 @@ static void nx_of_update_msc(struct device   *dev,
                                goto next_loop;
                        }
 
+                       if (!trip->sglen || trip->databytelen < NX_PAGE_SIZE) {
+                               dev_warn(dev, "bogus sglen/databytelen: "
+                                        "%u/%u (ignored)\n", trip->sglen,
+                                        trip->databytelen);
+                               goto next_loop;
+                       }
+
                        switch (trip->keybitlen) {
                        case 128:
                        case 160:
@@ -490,6 +498,72 @@ static void nx_of_init(struct device *dev, struct nx_of *props)
                nx_of_update_msc(dev, p, props);
 }
 
+static bool nx_check_prop(struct device *dev, u32 fc, u32 mode, int slot)
+{
+       struct alg_props *props = &nx_driver.of.ap[fc][mode][slot];
+
+       if (!props->sglen || props->databytelen < NX_PAGE_SIZE) {
+               if (dev)
+                       dev_warn(dev, "bogus sglen/databytelen for %u/%u/%u: "
+                                "%u/%u (ignored)\n", fc, mode, slot,
+                                props->sglen, props->databytelen);
+               return false;
+       }
+
+       return true;
+}
+
+static bool nx_check_props(struct device *dev, u32 fc, u32 mode)
+{
+       int i;
+
+       for (i = 0; i < 3; i++)
+               if (!nx_check_prop(dev, fc, mode, i))
+                       return false;
+
+       return true;
+}
+
+static int nx_register_alg(struct crypto_alg *alg, u32 fc, u32 mode)
+{
+       return nx_check_props(&nx_driver.viodev->dev, fc, mode) ?
+              crypto_register_alg(alg) : 0;
+}
+
+static int nx_register_aead(struct aead_alg *alg, u32 fc, u32 mode)
+{
+       return nx_check_props(&nx_driver.viodev->dev, fc, mode) ?
+              crypto_register_aead(alg) : 0;
+}
+
+static int nx_register_shash(struct shash_alg *alg, u32 fc, u32 mode, int slot)
+{
+       return (slot >= 0 ? nx_check_prop(&nx_driver.viodev->dev,
+                                         fc, mode, slot) :
+                           nx_check_props(&nx_driver.viodev->dev, fc, mode)) ?
+              crypto_register_shash(alg) : 0;
+}
+
+static void nx_unregister_alg(struct crypto_alg *alg, u32 fc, u32 mode)
+{
+       if (nx_check_props(NULL, fc, mode))
+               crypto_unregister_alg(alg);
+}
+
+static void nx_unregister_aead(struct aead_alg *alg, u32 fc, u32 mode)
+{
+       if (nx_check_props(NULL, fc, mode))
+               crypto_unregister_aead(alg);
+}
+
+static void nx_unregister_shash(struct shash_alg *alg, u32 fc, u32 mode,
+                               int slot)
+{
+       if (slot >= 0 ? nx_check_prop(NULL, fc, mode, slot) :
+                       nx_check_props(NULL, fc, mode))
+               crypto_unregister_shash(alg);
+}
+
 /**
  * nx_register_algs - register algorithms with the crypto API
  *
@@ -514,72 +588,77 @@ static int nx_register_algs(void)
 
        nx_driver.of.status = NX_OKAY;
 
-       rc = crypto_register_alg(&nx_ecb_aes_alg);
+       rc = nx_register_alg(&nx_ecb_aes_alg, NX_FC_AES, NX_MODE_AES_ECB);
        if (rc)
                goto out;
 
-       rc = crypto_register_alg(&nx_cbc_aes_alg);
+       rc = nx_register_alg(&nx_cbc_aes_alg, NX_FC_AES, NX_MODE_AES_CBC);
        if (rc)
                goto out_unreg_ecb;
 
-       rc = crypto_register_alg(&nx_ctr_aes_alg);
+       rc = nx_register_alg(&nx_ctr_aes_alg, NX_FC_AES, NX_MODE_AES_CTR);
        if (rc)
                goto out_unreg_cbc;
 
-       rc = crypto_register_alg(&nx_ctr3686_aes_alg);
+       rc = nx_register_alg(&nx_ctr3686_aes_alg, NX_FC_AES, NX_MODE_AES_CTR);
        if (rc)
                goto out_unreg_ctr;
 
-       rc = crypto_register_aead(&nx_gcm_aes_alg);
+       rc = nx_register_aead(&nx_gcm_aes_alg, NX_FC_AES, NX_MODE_AES_GCM);
        if (rc)
                goto out_unreg_ctr3686;
 
-       rc = crypto_register_aead(&nx_gcm4106_aes_alg);
+       rc = nx_register_aead(&nx_gcm4106_aes_alg, NX_FC_AES, NX_MODE_AES_GCM);
        if (rc)
                goto out_unreg_gcm;
 
-       rc = crypto_register_alg(&nx_ccm_aes_alg);
+       rc = nx_register_alg(&nx_ccm_aes_alg, NX_FC_AES, NX_MODE_AES_CCM);
        if (rc)
                goto out_unreg_gcm4106;
 
-       rc = crypto_register_alg(&nx_ccm4309_aes_alg);
+       rc = nx_register_alg(&nx_ccm4309_aes_alg, NX_FC_AES, NX_MODE_AES_CCM);
        if (rc)
                goto out_unreg_ccm;
 
-       rc = crypto_register_shash(&nx_shash_sha256_alg);
+       rc = nx_register_shash(&nx_shash_sha256_alg, NX_FC_SHA, NX_MODE_SHA,
+                              NX_PROPS_SHA256);
        if (rc)
                goto out_unreg_ccm4309;
 
-       rc = crypto_register_shash(&nx_shash_sha512_alg);
+       rc = nx_register_shash(&nx_shash_sha512_alg, NX_FC_SHA, NX_MODE_SHA,
+                              NX_PROPS_SHA512);
        if (rc)
                goto out_unreg_s256;
 
-       rc = crypto_register_shash(&nx_shash_aes_xcbc_alg);
+       rc = nx_register_shash(&nx_shash_aes_xcbc_alg,
+                              NX_FC_AES, NX_MODE_AES_XCBC_MAC, -1);
        if (rc)
                goto out_unreg_s512;
 
        goto out;
 
 out_unreg_s512:
-       crypto_unregister_shash(&nx_shash_sha512_alg);
+       nx_unregister_shash(&nx_shash_sha512_alg, NX_FC_SHA, NX_MODE_SHA,
+                           NX_PROPS_SHA512);
 out_unreg_s256:
-       crypto_unregister_shash(&nx_shash_sha256_alg);
+       nx_unregister_shash(&nx_shash_sha256_alg, NX_FC_SHA, NX_MODE_SHA,
+                           NX_PROPS_SHA256);
 out_unreg_ccm4309:
-       crypto_unregister_alg(&nx_ccm4309_aes_alg);
+       nx_unregister_alg(&nx_ccm4309_aes_alg, NX_FC_AES, NX_MODE_AES_CCM);
 out_unreg_ccm:
-       crypto_unregister_alg(&nx_ccm_aes_alg);
+       nx_unregister_alg(&nx_ccm_aes_alg, NX_FC_AES, NX_MODE_AES_CCM);
 out_unreg_gcm4106:
-       crypto_unregister_aead(&nx_gcm4106_aes_alg);
+       nx_unregister_aead(&nx_gcm4106_aes_alg, NX_FC_AES, NX_MODE_AES_GCM);
 out_unreg_gcm:
-       crypto_unregister_aead(&nx_gcm_aes_alg);
+       nx_unregister_aead(&nx_gcm_aes_alg, NX_FC_AES, NX_MODE_AES_GCM);
 out_unreg_ctr3686:
-       crypto_unregister_alg(&nx_ctr3686_aes_alg);
+       nx_unregister_alg(&nx_ctr3686_aes_alg, NX_FC_AES, NX_MODE_AES_CTR);
 out_unreg_ctr:
-       crypto_unregister_alg(&nx_ctr_aes_alg);
+       nx_unregister_alg(&nx_ctr_aes_alg, NX_FC_AES, NX_MODE_AES_CTR);
 out_unreg_cbc:
-       crypto_unregister_alg(&nx_cbc_aes_alg);
+       nx_unregister_alg(&nx_cbc_aes_alg, NX_FC_AES, NX_MODE_AES_CBC);
 out_unreg_ecb:
-       crypto_unregister_alg(&nx_ecb_aes_alg);
+       nx_unregister_alg(&nx_ecb_aes_alg, NX_FC_AES, NX_MODE_AES_ECB);
 out:
        return rc;
 }
@@ -725,17 +804,24 @@ static int nx_remove(struct vio_dev *viodev)
        if (nx_driver.of.status == NX_OKAY) {
                NX_DEBUGFS_FINI(&nx_driver);
 
-               crypto_unregister_alg(&nx_ccm_aes_alg);
-               crypto_unregister_alg(&nx_ccm4309_aes_alg);
-               crypto_unregister_aead(&nx_gcm_aes_alg);
-               crypto_unregister_aead(&nx_gcm4106_aes_alg);
-               crypto_unregister_alg(&nx_ctr_aes_alg);
-               crypto_unregister_alg(&nx_ctr3686_aes_alg);
-               crypto_unregister_alg(&nx_cbc_aes_alg);
-               crypto_unregister_alg(&nx_ecb_aes_alg);
-               crypto_unregister_shash(&nx_shash_sha256_alg);
-               crypto_unregister_shash(&nx_shash_sha512_alg);
-               crypto_unregister_shash(&nx_shash_aes_xcbc_alg);
+               nx_unregister_shash(&nx_shash_aes_xcbc_alg,
+                                   NX_FC_AES, NX_MODE_AES_XCBC_MAC, -1);
+               nx_unregister_shash(&nx_shash_sha512_alg,
+                                   NX_FC_SHA, NX_MODE_SHA, NX_PROPS_SHA256);
+               nx_unregister_shash(&nx_shash_sha256_alg,
+                                   NX_FC_SHA, NX_MODE_SHA, NX_PROPS_SHA512);
+               nx_unregister_alg(&nx_ccm4309_aes_alg,
+                                 NX_FC_AES, NX_MODE_AES_CCM);
+               nx_unregister_alg(&nx_ccm_aes_alg, NX_FC_AES, NX_MODE_AES_CCM);
+               nx_unregister_aead(&nx_gcm4106_aes_alg,
+                                  NX_FC_AES, NX_MODE_AES_GCM);
+               nx_unregister_aead(&nx_gcm_aes_alg,
+                                  NX_FC_AES, NX_MODE_AES_GCM);
+               nx_unregister_alg(&nx_ctr3686_aes_alg,
+                                 NX_FC_AES, NX_MODE_AES_CTR);
+               nx_unregister_alg(&nx_ctr_aes_alg, NX_FC_AES, NX_MODE_AES_CTR);
+               nx_unregister_alg(&nx_cbc_aes_alg, NX_FC_AES, NX_MODE_AES_CBC);
+               nx_unregister_alg(&nx_ecb_aes_alg, NX_FC_AES, NX_MODE_AES_ECB);
        }
 
        return 0;