From d7fc953fa2dd0ca69677a57d26c8aebf15f070ca Mon Sep 17 00:00:00 2001 From: Milan Broz Date: Thu, 29 Nov 2012 18:01:02 +0100 Subject: [PATCH] Handle kernel crypto api init failure better. --- lib/crypto_backend/crypto_cipher_kernel.c | 50 ++++++++++++++++++++----------- lib/tcrypt/tcrypt.c | 20 +++++++++---- src/cryptsetup.c | 13 ++++++-- 3 files changed, 57 insertions(+), 26 deletions(-) diff --git a/lib/crypto_backend/crypto_cipher_kernel.c b/lib/crypto_backend/crypto_cipher_kernel.c index 79eeb0d..ddd6678 100644 --- a/lib/crypto_backend/crypto_cipher_kernel.c +++ b/lib/crypto_backend/crypto_cipher_kernel.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #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) { diff --git a/lib/tcrypt/tcrypt.c b/lib/tcrypt/tcrypt.c index 4d2cdb3..373637d 100644 --- a/lib/tcrypt/tcrypt.c +++ b/lib/tcrypt/tcrypt.c @@ -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)) { diff --git a/src/cryptsetup.c b/src/cryptsetup.c index 7501fd6..31896f2 100644 --- a/src/cryptsetup.c +++ b/src/cryptsetup.c @@ -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; } -- 2.7.4