From c35fcdc0b70dac524dbea36cd69b6ac0febbe992 Mon Sep 17 00:00:00 2001 From: Vladimir Serbinenko Date: Tue, 12 Nov 2013 02:48:02 +0100 Subject: [PATCH] * grub-core/disk/AFSplitter.c: Remove variable length arrays. * grub-core/disk/cryptodisk.c: Likewise. * grub-core/disk/geli.c: Likewise. * grub-core/disk/luks.c: Likewise. --- ChangeLog | 7 +++++++ grub-core/disk/AFSplitter.c | 7 +++++-- grub-core/disk/cryptodisk.c | 26 ++++++++++++++++++------- grub-core/disk/geli.c | 38 +++++++++++++++++++++++++------------ grub-core/disk/luks.c | 6 ++++-- 5 files changed, 61 insertions(+), 23 deletions(-) diff --git a/ChangeLog b/ChangeLog index dc1699e97..661d4d2e8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2013-11-12 Vladimir Serbinenko + + * grub-core/disk/AFSplitter.c: Remove variable length arrays. + * grub-core/disk/cryptodisk.c: Likewise. + * grub-core/disk/geli.c: Likewise. + * grub-core/disk/luks.c: Likewise. + 2013-11-12 Vladimir Serbinenko * grub-core/tests/legacy_password_test.c: New test. diff --git a/grub-core/disk/AFSplitter.c b/grub-core/disk/AFSplitter.c index ebcc35221..d76a1c447 100644 --- a/grub-core/disk/AFSplitter.c +++ b/grub-core/disk/AFSplitter.c @@ -37,8 +37,8 @@ diffuse (const gcry_md_spec_t * hash, grub_uint8_t * src, grub_size_t fullblocks = size / hash->mdlen; int padding = size % hash->mdlen; - grub_uint8_t final[hash->mdlen]; - grub_uint8_t temp[sizeof (IV) + hash->mdlen]; + grub_uint8_t final[GRUB_CRYPTO_MAX_MDLEN]; + grub_uint8_t temp[sizeof (IV) + GRUB_CRYPTO_MAX_MDLEN]; /* hash block the whole data set with different IVs to produce * more than just a single data block @@ -76,6 +76,9 @@ AF_merge (const gcry_md_spec_t * hash, grub_uint8_t * src, grub_uint8_t * dst, if (bufblock == NULL) return GPG_ERR_OUT_OF_MEMORY; + if (hash->mdlen > GRUB_CRYPTO_MAX_MDLEN) + return GPG_ERR_INV_ARG; + grub_memset (bufblock, 0, blocksize); for (i = 0; i < blocknumbers - 1; i++) { diff --git a/grub-core/disk/cryptodisk.c b/grub-core/disk/cryptodisk.c index 1b40afc9d..a8a9b7171 100644 --- a/grub-core/disk/cryptodisk.c +++ b/grub-core/disk/cryptodisk.c @@ -109,7 +109,9 @@ grub_crypto_pcbc_decrypt (grub_crypto_cipher_handle_t cipher, void *iv) { grub_uint8_t *inptr, *outptr, *end; - grub_uint8_t ivt[cipher->cipher->blocksize]; + grub_uint8_t ivt[GRUB_CRYPTO_MAX_CIPHER_BLOCKSIZE]; + if (cipher->cipher->blocksize > GRUB_CRYPTO_MAX_CIPHER_BLOCKSIZE) + return GPG_ERR_INV_ARG; if (!cipher->cipher->decrypt) return GPG_ERR_NOT_SUPPORTED; if (size % cipher->cipher->blocksize != 0) @@ -132,7 +134,9 @@ grub_crypto_pcbc_encrypt (grub_crypto_cipher_handle_t cipher, void *iv) { grub_uint8_t *inptr, *outptr, *end; - grub_uint8_t ivt[cipher->cipher->blocksize]; + grub_uint8_t ivt[GRUB_CRYPTO_MAX_CIPHER_BLOCKSIZE]; + if (cipher->cipher->blocksize > GRUB_CRYPTO_MAX_CIPHER_BLOCKSIZE) + return GPG_ERR_INV_ARG; if (!cipher->cipher->decrypt) return GPG_ERR_NOT_SUPPORTED; if (size % cipher->cipher->blocksize != 0) @@ -218,6 +222,9 @@ grub_cryptodisk_endecrypt (struct grub_cryptodisk *dev, grub_size_t i; gcry_err_code_t err; + if (dev->cipher->cipher->blocksize > GRUB_CRYPTO_MAX_CIPHER_BLOCKSIZE) + return GPG_ERR_INV_ARG; + /* The only mode without IV. */ if (dev->mode == GRUB_CRYPTODISK_MODE_ECB && !dev->rekey) return (do_encrypt ? grub_crypto_ecb_encrypt (dev->cipher, data, data, len) @@ -228,7 +235,7 @@ grub_cryptodisk_endecrypt (struct grub_cryptodisk *dev, grub_size_t sz = ((dev->cipher->cipher->blocksize + sizeof (grub_uint32_t) - 1) / sizeof (grub_uint32_t)); - grub_uint32_t iv[sz]; + grub_uint32_t iv[(GRUB_CRYPTO_MAX_CIPHER_BLOCKSIZE + 3) / 4]; if (dev->rekey) { @@ -242,7 +249,7 @@ grub_cryptodisk_endecrypt (struct grub_cryptodisk *dev, } } - grub_memset (iv, 0, sz * sizeof (iv[0])); + grub_memset (iv, 0, sizeof (iv)); switch (dev->mode_iv) { case GRUB_CRYPTODISK_MODE_IV_NULL: @@ -250,9 +257,11 @@ grub_cryptodisk_endecrypt (struct grub_cryptodisk *dev, case GRUB_CRYPTODISK_MODE_IV_BYTECOUNT64_HASH: { grub_uint64_t tmp; - GRUB_PROPERLY_ALIGNED_ARRAY (ctx, dev->iv_hash->contextsize); + void *ctx; - grub_memset (ctx, 0, sizeof (ctx)); + ctx = grub_zalloc (dev->iv_hash->contextsize); + if (!ctx) + return GPG_ERR_OUT_OF_MEMORY; tmp = grub_cpu_to_le64 (sector << dev->log_sector_size); dev->iv_hash->init (ctx); @@ -261,6 +270,7 @@ grub_cryptodisk_endecrypt (struct grub_cryptodisk *dev, dev->iv_hash->final (ctx); grub_memcpy (iv, dev->iv_hash->read (ctx), sizeof (iv)); + grub_free (ctx); } break; case GRUB_CRYPTODISK_MODE_IV_PLAIN64: @@ -407,7 +417,9 @@ grub_cryptodisk_setkey (grub_cryptodisk_t dev, grub_uint8_t *key, grub_size_t ke if (dev->mode_iv == GRUB_CRYPTODISK_MODE_IV_ESSIV) { grub_size_t essiv_keysize = dev->essiv_hash->mdlen; - grub_uint8_t hashed_key[essiv_keysize]; + grub_uint8_t hashed_key[GRUB_CRYPTO_MAX_MDLEN]; + if (essiv_keysize > GRUB_CRYPTO_MAX_MDLEN) + return GPG_ERR_INV_ARG; grub_crypto_hash (dev->essiv_hash, hashed_key, key, keysize); err = grub_crypto_cipher_set_key (dev->essiv_cipher, diff --git a/grub-core/disk/geli.c b/grub-core/disk/geli.c index 7e3e09e72..73b325c94 100644 --- a/grub-core/disk/geli.c +++ b/grub-core/disk/geli.c @@ -146,7 +146,10 @@ geli_rekey (struct grub_cryptodisk *dev, grub_uint64_t zoneno) grub_uint64_t zone; } __attribute__ ((packed)) tohash = { {'e', 'k', 'e', 'y'}, grub_cpu_to_le64 (zoneno) }; - GRUB_PROPERLY_ALIGNED_ARRAY (key, dev->hash->mdlen); + GRUB_PROPERLY_ALIGNED_ARRAY (key, GRUB_CRYPTO_MAX_MDLEN); + + if (dev->hash->mdlen > GRUB_CRYPTO_MAX_MDLEN) + return GPG_ERR_INV_ARG; grub_dprintf ("geli", "rekeying %" PRIuGRUB_UINT64_T " keysize=%d\n", zoneno, dev->rekey_derived_size); @@ -163,11 +166,13 @@ static inline gcry_err_code_t make_uuid (const struct grub_geli_phdr *header, char *uuid) { - grub_uint8_t uuidbin[GRUB_MD_SHA256->mdlen]; + grub_uint8_t uuidbin[GRUB_CRYPTODISK_MAX_UUID_LENGTH]; gcry_err_code_t err; grub_uint8_t *iptr; char *optr; + if (2 * GRUB_MD_SHA256->mdlen + 1 > GRUB_CRYPTODISK_MAX_UUID_LENGTH) + return GPG_ERR_TOO_LARGE; err = grub_crypto_hmac_buffer (GRUB_MD_SHA256, header->salt, sizeof (header->salt), "uuid", sizeof ("uuid") - 1, uuidbin); @@ -175,7 +180,7 @@ make_uuid (const struct grub_geli_phdr *header, return err; optr = uuid; - for (iptr = uuidbin; iptr < &uuidbin[ARRAY_SIZE (uuidbin)]; iptr++) + for (iptr = uuidbin; iptr < &uuidbin[GRUB_MD_SHA256->mdlen]; iptr++) { grub_snprintf (optr, 3, "%02x", *iptr); optr += 2; @@ -242,10 +247,13 @@ configure_ciphers (grub_disk_t disk, const char *check_uuid, const struct gcry_cipher_spec *ciph; const char *ciphername = NULL; gcry_err_code_t gcry_err; - char uuid[GRUB_MD_SHA256->mdlen * 2 + 1]; + char uuid[GRUB_CRYPTODISK_MAX_UUID_LENGTH]; grub_disk_addr_t sector; grub_err_t err; + if (2 * GRUB_MD_SHA256->mdlen + 1 > GRUB_CRYPTODISK_MAX_UUID_LENGTH) + return NULL; + sector = grub_disk_get_size (disk); if (sector == GRUB_DISK_SIZE_UNKNOWN || sector == 0) return NULL; @@ -379,10 +387,10 @@ static grub_err_t recover_key (grub_disk_t source, grub_cryptodisk_t dev) { grub_size_t keysize; - grub_uint8_t digest[dev->hash->mdlen]; - grub_uint8_t geomkey[dev->hash->mdlen]; - grub_uint8_t verify_key[dev->hash->mdlen]; - grub_uint8_t zero[dev->cipher->cipher->blocksize]; + grub_uint8_t digest[GRUB_CRYPTO_MAX_MDLEN]; + grub_uint8_t geomkey[GRUB_CRYPTO_MAX_MDLEN]; + grub_uint8_t verify_key[GRUB_CRYPTO_MAX_MDLEN]; + grub_uint8_t zero[GRUB_CRYPTO_MAX_CIPHER_BLOCKSIZE]; char passphrase[MAX_PASSPHRASE] = ""; unsigned i; gcry_err_code_t gcry_err; @@ -391,6 +399,12 @@ recover_key (grub_disk_t source, grub_cryptodisk_t dev) grub_disk_addr_t sector; grub_err_t err; + if (dev->cipher->cipher->blocksize > GRUB_CRYPTO_MAX_CIPHER_BLOCKSIZE) + return grub_error (GRUB_ERR_BUG, "cipher block is too long"); + + if (dev->hash->mdlen > GRUB_CRYPTO_MAX_MDLEN) + return grub_error (GRUB_ERR_BUG, "mdlen is too long"); + sector = grub_disk_get_size (source); if (sector == GRUB_DISK_SIZE_UNKNOWN || sector == 0) return grub_error (GRUB_ERR_BUG, "not a geli"); @@ -452,12 +466,12 @@ recover_key (grub_disk_t source, grub_cryptodisk_t dev) } gcry_err = grub_crypto_hmac_buffer (dev->hash, geomkey, - sizeof (geomkey), "\1", 1, digest); + dev->hash->mdlen, "\1", 1, digest); if (gcry_err) return grub_crypto_gcry_error (gcry_err); gcry_err = grub_crypto_hmac_buffer (dev->hash, geomkey, - sizeof (geomkey), "\0", 1, verify_key); + dev->hash->mdlen, "\0", 1, verify_key); if (gcry_err) return grub_crypto_gcry_error (gcry_err); @@ -467,7 +481,7 @@ recover_key (grub_disk_t source, grub_cryptodisk_t dev) for (i = 0; i < ARRAY_SIZE (header.keys); i++) { struct grub_geli_key candidate_key; - grub_uint8_t key_hmac[dev->hash->mdlen]; + grub_uint8_t key_hmac[GRUB_CRYPTO_MAX_MDLEN]; /* Check if keyslot is enabled. */ if (! (header.keys_used & (1 << i))) @@ -488,7 +502,7 @@ recover_key (grub_disk_t source, grub_cryptodisk_t dev) return grub_crypto_gcry_error (gcry_err); gcry_err = grub_crypto_hmac_buffer (dev->hash, verify_key, - sizeof (verify_key), + dev->hash->mdlen, &candidate_key, (sizeof (candidate_key) - sizeof (candidate_key.hmac)), diff --git a/grub-core/disk/luks.c b/grub-core/disk/luks.c index b98055294..46f47c2b6 100644 --- a/grub-core/disk/luks.c +++ b/grub-core/disk/luks.c @@ -316,6 +316,8 @@ luks_recover_key (grub_disk_t source, grub_puts_ (N_("Attempting to decrypt master key...")); keysize = grub_be_to_cpu32 (header.keyBytes); + if (keysize > GRUB_CRYPTODISK_MAX_KEYLEN) + return grub_error (GRUB_ERR_BAD_FS, "key is too long"); for (i = 0; i < ARRAY_SIZE (header.keyblock); i++) if (grub_be_to_cpu32 (header.keyblock[i].active) == LUKS_KEY_ENABLED @@ -344,8 +346,8 @@ luks_recover_key (grub_disk_t source, for (i = 0; i < ARRAY_SIZE (header.keyblock); i++) { gcry_err_code_t gcry_err; - grub_uint8_t candidate_key[keysize]; - grub_uint8_t digest[keysize]; + grub_uint8_t candidate_key[GRUB_CRYPTODISK_MAX_KEYLEN]; + grub_uint8_t digest[GRUB_CRYPTODISK_MAX_KEYLEN]; /* Check if keyslot is enabled. */ if (grub_be_to_cpu32 (header.keyblock[i].active) != LUKS_KEY_ENABLED)