Handle kernel crypto api init failure better.
authorMilan Broz <gmazyland@gmail.com>
Thu, 29 Nov 2012 17:01:02 +0000 (18:01 +0100)
committerMilan Broz <gmazyland@gmail.com>
Thu, 29 Nov 2012 17:01:02 +0000 (18:01 +0100)
lib/crypto_backend/crypto_cipher_kernel.c
lib/tcrypt/tcrypt.c
src/cryptsetup.c

index 79eeb0d..ddd6678 100644 (file)
@@ -24,6 +24,7 @@
 #include <errno.h>
 #include <unistd.h>
 #include <sys/socket.h>
+#include <sys/stat.h>
 #include <linux/if_alg.h>
 #include "crypto_backend.h"
 
@@ -43,29 +44,40 @@ int crypt_kernel_socket_init(struct sockaddr_alg *sa, int *tfmfd, int *opfd)
 {
        *tfmfd = socket(AF_ALG, SOCK_SEQPACKET, 0);
        if (*tfmfd == -1)
-               goto bad;
+               return -ENOENT;
 
-       if (bind(*tfmfd, (struct sockaddr *)sa, sizeof(*sa)) == -1)
-               goto bad;
+       if (bind(*tfmfd, (struct sockaddr *)sa, sizeof(*sa)) == -1) {
+               close(*tfmfd);
+               *tfmfd = -1;
+               return -ENOENT;
+       }
 
        *opfd = accept(*tfmfd, NULL, 0);
-       if (*opfd == -1)
-               goto bad;
-
-       return 0;
-bad:
-       if (*tfmfd != -1) {
+       if (*opfd == -1) {
                close(*tfmfd);
                *tfmfd = -1;
+               return -EINVAL;
        }
-       if (*opfd != -1) {
-               close(*opfd);
-               *opfd = -1;
-       }
-       return -EINVAL;
+
+       return 0;
+}
+
+static int crypt_kernel_cipher_available(void)
+{
+       struct stat st;
+
+       if(stat("/sys/module/algif_skcipher", &st) < 0)
+               return -ENOENT;
+
+       return -ENOTSUP;
 }
 
-/* ciphers */
+/*
+ *ciphers
+ *
+ * ENOENT - no API available
+ * ENOTSUP - algorithm not available
+ */
 int crypt_cipher_init(struct crypt_cipher **ctx, const char *name,
                    const char *mode, const void *buffer, size_t length)
 {
@@ -74,6 +86,7 @@ int crypt_cipher_init(struct crypt_cipher **ctx, const char *name,
                .salg_family = AF_ALG,
                .salg_type = "skcipher",
        };
+       int r;
 
        h = malloc(sizeof(*h));
        if (!h)
@@ -82,9 +95,12 @@ int crypt_cipher_init(struct crypt_cipher **ctx, const char *name,
        snprintf((char *)sa.salg_name, sizeof(sa.salg_name),
                 "%s(%s)", mode, name);
 
-       if (crypt_kernel_socket_init(&sa, &h->tfmfd, &h->opfd) < 0) {
+       r = crypt_kernel_socket_init(&sa, &h->tfmfd, &h->opfd);
+       if (r < 0) {
                free(h);
-               return -ENOTSUP;
+               if (r == -ENOENT)
+                       return crypt_kernel_cipher_available();
+               return r;
        }
 
        if (setsockopt(h->tfmfd, SOL_ALG, ALG_SET_KEY, buffer, length) == -1) {
index 4d2cdb3..373637d 100644 (file)
@@ -244,7 +244,7 @@ static int decrypt_blowfish_le_cbc(struct tcrypt_alg *alg,
        r = crypt_cipher_init(&cipher, "blowfish", "ecb",
                              &key[alg->key_offset], alg->key_size);
        if (r < 0)
-               goto out;
+               return r;
 
        memcpy(iv, &key[alg->iv_offset], alg->iv_size);
        for (i = 0; i < TCRYPT_HDR_LEN; i += bs) {
@@ -254,12 +254,12 @@ static int decrypt_blowfish_le_cbc(struct tcrypt_alg *alg,
                                          bs, NULL, 0);
                blowfish_le(&buf[i]);
                if (r < 0)
-                       goto out;
+                       break;
                for (j = 0; j < bs; j++)
                        buf[i + j] ^= iv[j];
                memcpy(iv, iv_old, bs);
        }
-out:
+
        crypt_cipher_destroy(cipher);
        return r;
 }
@@ -394,10 +394,18 @@ static int decrypt_hdr(struct crypt_device *cd, struct tcrypt_phdr *hdr,
                                continue;
                        r = decrypt_hdr_one(&tcrypt_cipher[i].cipher[j],
                                            tcrypt_cipher[i].mode, key, &hdr2);
-                       if (r < 0) {
-                               log_dbg("Error %s.", tcrypt_cipher[i].cipher[j].name);
+                       if (r < 0)
                                break;
-                       }
+               }
+
+               if (r == -ENOENT) {
+                       log_err(cd, _("Required kernel crypto interface is not available.\n"
+                                     "Ensure you have af_skcipher kernel module loaded.\n"));
+                       return -ENOTSUP;
+               }
+               if (r < 0) {
+                       log_dbg("TCRYPT:   returned error %d, skipped.", r);
+                       continue;
                }
 
                if (!strncmp(hdr2.d.magic, TCRYPT_HDR_MAGIC, TCRYPT_HDR_MAGIC_LEN)) {
index 7501fd6..31896f2 100644 (file)
@@ -489,14 +489,18 @@ static int action_benchmark(int arg __attribute__((unused)))
                        strncat(cipher, cipher_mode, MAX_CIPHER_LEN);
                        log_std("%11s  %4db  %5.1f MiB/s  %5.1f MiB/s\n",
                                cipher, key_size, enc_mbr, dec_mbr);
-               } else
-                       log_err(_("Cannot benchmark %s.\n"), cipher);
+               } else if (r == -ENOTSUP)
+                       log_err(_("Cipher %s is not available.\n"), opt_cipher);
        } else {
-               log_std("%s", header);
                for (i = 0; bciphers[i].cipher; i++) {
                        r = crypt_benchmark(NULL, bciphers[i].cipher, bciphers[i].mode,
                                            bciphers[i].key_size, bciphers[i].iv_size,
                                            buffer_size, &enc_mbr, &dec_mbr);
+                       if (r == -ENOENT)
+                               break;
+                       if (i == 0)
+                               log_std("%s", header);
+
                        snprintf(cipher, MAX_CIPHER_LEN, "%s-%s",
                                 bciphers[i].cipher, bciphers[i].mode);
                        if (!r)
@@ -508,6 +512,9 @@ static int action_benchmark(int arg __attribute__((unused)))
                }
        }
 
+       if (r == -ENOENT)
+               log_err( _("Required kernel crypto interface is not available.\n"
+                          "Ensure you have af_skcipher kernel module loaded.\n"));
        return r;
 }