diff --git a/lib/Makemodule.am b/lib/Makemodule.am index a0fc0d22..02b3b8d4 100644 --- a/lib/Makemodule.am +++ b/lib/Makemodule.am @@ -64,6 +64,7 @@ libcryptsetup_la_SOURCES = \ lib/utils_device_locking.c \ lib/utils_device_locking.h \ lib/utils_pbkdf.c \ + lib/utils_safe_memory.c \ lib/utils_storage_wrappers.c \ lib/utils_storage_wrappers.h \ lib/libdevmapper.c \ diff --git a/lib/libcryptsetup.h b/lib/libcryptsetup.h index faeb2a72..103ba911 100644 --- a/lib/libcryptsetup.h +++ b/lib/libcryptsetup.h @@ -2251,6 +2251,53 @@ crypt_reencrypt_info crypt_reencrypt_status(struct crypt_device *cd, struct crypt_params_reencrypt *params); /** @} */ +/** + * @defgroup crypt-memory Safe memory helpers functions + * @addtogroup crypt-memory + * @{ + */ + +/** + * Allocate safe memory (content is safely wiped on deallocation). + * + * @param size size of memory in bytes + * + * @return pointer to allocate memory or @e NULL. + */ +void *crypt_safe_alloc(size_t size); + +/** + * Release safe memory, content is safely wiped + * The pointer must be allocated with @link crypt_safe_alloc @endlink + * + * @param data pointer to memory to be deallocated + * + * @return pointer to allocate memory or @e NULL. + */ +void crypt_safe_free(void *data); + +/** + * Reallocate safe memory (content is copied and safely wiped on deallocation). + * + * @param data pointer to memory to be deallocated + * @param size new size of memory in bytes + * + * @return pointer to allocate memory or @e NULL. + */ +void *crypt_safe_realloc(void *data, size_t size); + +/** + * Safe clear memory area (compile should not compile this call out). + * + * @param data pointer to memory to cleared + * @param size new size of memory in bytes + * + * @return pointer to allocate memory or @e NULL. + */ +void crypt_safe_memzero(void *data, size_t size); + +/** @} */ + #ifdef __cplusplus } #endif diff --git a/lib/libcryptsetup.sym b/lib/libcryptsetup.sym index b360021b..70b610a4 100644 --- a/lib/libcryptsetup.sym +++ b/lib/libcryptsetup.sym @@ -118,6 +118,11 @@ CRYPTSETUP_2.0 { crypt_reencrypt_init_by_keyring; crypt_reencrypt; crypt_reencrypt_status; + + crypt_safe_alloc; + crypt_safe_realloc; + crypt_safe_free; + crypt_safe_memzero; local: *; }; diff --git a/lib/luks1/keymanage.c b/lib/luks1/keymanage.c index 6ef69a00..af4d54a6 100644 --- a/lib/luks1/keymanage.c +++ b/lib/luks1/keymanage.c @@ -260,7 +260,7 @@ int LUKS_hdr_backup(const char *backup_file, struct crypt_device *ctx) r = 0; out: - crypt_memzero(&hdr, sizeof(hdr)); + crypt_safe_memzero(&hdr, sizeof(hdr)); crypt_safe_free(buffer); return r; } @@ -453,7 +453,7 @@ out: if (r) log_err(ctx, _("Repair failed.")); crypt_free_volume_key(vk); - crypt_memzero(&temp_phdr, sizeof(temp_phdr)); + crypt_safe_memzero(&temp_phdr, sizeof(temp_phdr)); return r; } @@ -692,7 +692,7 @@ int LUKS_check_cipher(struct crypt_device *ctx, size_t keylength, const char *ci r = LUKS_decrypt_from_storage(buf, sizeof(buf), cipher, cipher_mode, empty_key, 0, ctx); crypt_free_volume_key(empty_key); - crypt_memzero(buf, sizeof(buf)); + crypt_safe_memzero(buf, sizeof(buf)); return r; } diff --git a/lib/luks2/luks2_json_metadata.c b/lib/luks2/luks2_json_metadata.c index 3554e322..a143b3b3 100644 --- a/lib/luks2/luks2_json_metadata.c +++ b/lib/luks2/luks2_json_metadata.c @@ -1270,8 +1270,8 @@ out: LUKS2_hdr_free(cd, hdr); LUKS2_hdr_free(cd, &hdr_file); LUKS2_hdr_free(cd, &tmp_hdr); - crypt_memzero(&hdr_file, sizeof(hdr_file)); - crypt_memzero(&tmp_hdr, sizeof(tmp_hdr)); + crypt_safe_memzero(&hdr_file, sizeof(hdr_file)); + crypt_safe_memzero(&tmp_hdr, sizeof(tmp_hdr)); crypt_safe_free(buffer); device_sync(cd, device); diff --git a/lib/luks2/luks2_luks1_convert.c b/lib/luks2/luks2_luks1_convert.c index 7f5f26b7..5f99efa8 100644 --- a/lib/luks2/luks2_luks1_convert.c +++ b/lib/luks2/luks2_luks1_convert.c @@ -466,7 +466,7 @@ static int move_keyslot_areas(struct crypt_device *cd, off_t offset_from, r = 0; out: device_sync(cd, device); - crypt_memzero(buf, buf_size); + crypt_safe_memzero(buf, buf_size); free(buf); return r; diff --git a/lib/luks2/luks2_reencrypt.c b/lib/luks2/luks2_reencrypt.c index 6bac4420..718f3477 100644 --- a/lib/luks2/luks2_reencrypt.c +++ b/lib/luks2/luks2_reencrypt.c @@ -1401,12 +1401,12 @@ static int reencrypt_recover_segment(struct crypt_device *cd, log_dbg(cd, "Failed to read journaled data."); r = -EIO; /* may content plaintext */ - crypt_memzero(data_buffer, rh->length); + crypt_safe_memzero(data_buffer, rh->length); goto out; } read = crypt_storage_wrapper_encrypt_write(cw2, 0, data_buffer, rh->length); /* may content plaintext */ - crypt_memzero(data_buffer, rh->length); + crypt_safe_memzero(data_buffer, rh->length); if (read < 0 || (size_t)read != rh->length) { log_dbg(cd, "recovery write failed."); r = -EINVAL; @@ -1436,13 +1436,13 @@ static int reencrypt_recover_segment(struct crypt_device *cd, log_dbg(cd, "Failed to read data."); r = -EIO; /* may content plaintext */ - crypt_memzero(data_buffer, rh->length); + crypt_safe_memzero(data_buffer, rh->length); goto out; } read = crypt_storage_wrapper_encrypt_write(cw2, 0, data_buffer, rh->length); /* may content plaintext */ - crypt_memzero(data_buffer, rh->length); + crypt_safe_memzero(data_buffer, rh->length); if (read < 0 || (size_t)read != rh->length) { log_dbg(cd, "recovery write failed."); r = -EINVAL; @@ -2936,7 +2936,7 @@ int crypt_reencrypt_init_by_keyring(struct crypt_device *cd, r = reencrypt_init_by_passphrase(cd, name, passphrase, passphrase_size, keyslot_old, keyslot_new, cipher, cipher_mode, params); - crypt_memzero(passphrase, passphrase_size); + crypt_safe_memzero(passphrase, passphrase_size); free(passphrase); return r; diff --git a/lib/luks2/luks2_token.c b/lib/luks2/luks2_token.c index 8355deb1..22a81e10 100644 --- a/lib/luks2/luks2_token.c +++ b/lib/luks2/luks2_token.c @@ -332,7 +332,7 @@ static void LUKS2_token_buffer_free(struct crypt_device *cd, if (h->buffer_free) h->buffer_free(buffer, buffer_len); else { - crypt_memzero(buffer, buffer_len); + crypt_safe_memzero(buffer, buffer_len); free(buffer); } } diff --git a/lib/setup.c b/lib/setup.c index 2e63ae9f..d48056f5 100644 --- a/lib/setup.c +++ b/lib/setup.c @@ -726,9 +726,6 @@ out: free(type); LUKS2_hdr_free(cd, &hdr2); } - /* FIXME: why? */ - crypt_memzero(&hdr2, sizeof(hdr2)); - return r; } @@ -822,7 +819,7 @@ static int _crypt_load_luks(struct crypt_device *cd, const char *requested_type, r = -EINVAL; } out: - crypt_memzero(&hdr, sizeof(hdr)); + crypt_safe_memzero(&hdr, sizeof(hdr)); return r; } @@ -886,7 +883,7 @@ static int _crypt_load_verity(struct crypt_device *cd, struct crypt_params_verit free(CONST_CAST(void*)cd->u.verity.hdr.hash_name); free(CONST_CAST(void*)cd->u.verity.hdr.salt); free(cd->u.verity.uuid); - crypt_memzero(&cd->u.verity.hdr, sizeof(cd->u.verity.hdr)); + crypt_safe_memzero(&cd->u.verity.hdr, sizeof(cd->u.verity.hdr)); return -ENOMEM; } @@ -2902,8 +2899,8 @@ int crypt_header_restore(struct crypt_device *cd, else r = LUKS2_hdr_restore(cd, &hdr2, backup_file); - crypt_memzero(&hdr1, sizeof(hdr1)); - crypt_memzero(&hdr2, sizeof(hdr2)); + crypt_safe_memzero(&hdr1, sizeof(hdr1)); + crypt_safe_memzero(&hdr2, sizeof(hdr2)); } else if (isLUKS2(cd->type) && (!requested_type || isLUKS2(requested_type))) { r = LUKS2_hdr_restore(cd, &cd->u.luks2.hdr, backup_file); if (r) @@ -2938,7 +2935,7 @@ void crypt_free(struct crypt_device *cd) free(CONST_CAST(void*)cd->pbkdf.hash); /* Some structures can contain keys (TCRYPT), wipe it */ - crypt_memzero(cd, sizeof(*cd)); + crypt_safe_memzero(cd, sizeof(*cd)); free(cd); } @@ -5770,7 +5767,7 @@ int crypt_activate_by_keyring(struct crypt_device *cd, r = _activate_by_passphrase(cd, name, keyslot, passphrase, passphrase_size, flags); - crypt_memzero(passphrase, passphrase_size); + crypt_safe_memzero(passphrase, passphrase_size); free(passphrase); return r; diff --git a/lib/tcrypt/tcrypt.c b/lib/tcrypt/tcrypt.c index 49067aa9..712977de 100644 --- a/lib/tcrypt/tcrypt.c +++ b/lib/tcrypt/tcrypt.c @@ -301,8 +301,8 @@ static int decrypt_blowfish_le_cbc(struct tcrypt_alg *alg, } crypt_cipher_destroy(cipher); - crypt_memzero(iv, bs); - crypt_memzero(iv_old, bs); + crypt_safe_memzero(iv, bs); + crypt_safe_memzero(iv_old, bs); return r; } @@ -369,8 +369,8 @@ static int TCRYPT_decrypt_hdr_one(struct tcrypt_alg *alg, const char *mode, crypt_cipher_destroy(cipher); } - crypt_memzero(backend_key, sizeof(backend_key)); - crypt_memzero(iv, TCRYPT_HDR_IV_LEN); + crypt_safe_memzero(backend_key, sizeof(backend_key)); + crypt_safe_memzero(iv, TCRYPT_HDR_IV_LEN); return r; } @@ -420,8 +420,8 @@ out: if (cipher[j]) crypt_cipher_destroy(cipher[j]); - crypt_memzero(iv, bs); - crypt_memzero(iv_old, bs); + crypt_safe_memzero(iv, bs); + crypt_safe_memzero(iv_old, bs); return r; } @@ -474,7 +474,7 @@ static int TCRYPT_decrypt_hdr(struct crypt_device *cd, struct tcrypt_phdr *hdr, r = -EPERM; } - crypt_memzero(&hdr2, sizeof(hdr2)); + crypt_safe_memzero(&hdr2, sizeof(hdr2)); return r; } @@ -516,8 +516,8 @@ static int TCRYPT_pool_keyfile(struct crypt_device *cd, } r = 0; out: - crypt_memzero(&crc, sizeof(crc)); - crypt_memzero(data, TCRYPT_KEYFILE_LEN); + crypt_safe_memzero(&crc, sizeof(crc)); + crypt_safe_memzero(data, TCRYPT_KEYFILE_LEN); free(data); return r; @@ -619,9 +619,9 @@ static int TCRYPT_init_hdr(struct crypt_device *cd, params->cipher, params->mode, params->key_size); } out: - crypt_memzero(pwd, TCRYPT_KEY_POOL_LEN); + crypt_safe_memzero(pwd, TCRYPT_KEY_POOL_LEN); if (key) - crypt_memzero(key, TCRYPT_HDR_KEY_LEN); + crypt_safe_memzero(key, TCRYPT_HDR_KEY_LEN); free(key); return r; } diff --git a/lib/utils.c b/lib/utils.c index d9fb0683..e2bbccf3 100644 --- a/lib/utils.c +++ b/lib/utils.c @@ -130,7 +130,7 @@ static int keyfile_seek(int fd, uint64_t bytes) if (errno == EINTR) continue; - crypt_memzero(tmp, sizeof(tmp)); + crypt_safe_memzero(tmp, sizeof(tmp)); /* read error */ return -1; } @@ -142,7 +142,7 @@ static int keyfile_seek(int fd, uint64_t bytes) bytes -= bytes_r; } - crypt_memzero(tmp, sizeof(tmp)); + crypt_safe_memzero(tmp, sizeof(tmp)); return bytes == 0 ? 0 : -1; } @@ -181,7 +181,7 @@ int crypt_keyfile_device_read(struct crypt_device *cd, const char *keyfile, key_size = DEFAULT_KEYFILE_SIZE_MAXKB * 1024 + 1; unlimited_read = 1; /* use 4k for buffer (page divisor but avoid huge pages) */ - buflen = 4096 - sizeof(struct safe_allocation); + buflen = 4096 - sizeof(size_t); // sizeof(struct safe_allocation); } else buflen = key_size; diff --git a/lib/utils_crypt.c b/lib/utils_crypt.c index 6b189c9f..825be2d4 100644 --- a/lib/utils_crypt.c +++ b/lib/utils_crypt.c @@ -149,79 +149,6 @@ int crypt_parse_pbkdf(const char *s, const char **pbkdf) return 0; } -/* - * Replacement for memset(s, 0, n) on stack that can be optimized out - * Also used in safe allocations for explicit memory wipe. - */ -void crypt_memzero(void *s, size_t n) -{ -#ifdef HAVE_EXPLICIT_BZERO - explicit_bzero(s, n); -#else - volatile uint8_t *p = (volatile uint8_t *)s; - - while(n--) - *p++ = 0; -#endif -} - -/* safe allocations */ -void *crypt_safe_alloc(size_t size) -{ - struct safe_allocation *alloc; - - if (!size || size > (SIZE_MAX - offsetof(struct safe_allocation, data))) - return NULL; - - alloc = malloc(size + offsetof(struct safe_allocation, data)); - if (!alloc) - return NULL; - - alloc->size = size; - crypt_memzero(&alloc->data, size); - - /* coverity[leaked_storage] */ - return &alloc->data; -} - -void crypt_safe_free(void *data) -{ - struct safe_allocation *alloc; - - if (!data) - return; - - alloc = (struct safe_allocation *) - ((char *)data - offsetof(struct safe_allocation, data)); - - crypt_memzero(data, alloc->size); - - alloc->size = 0x55aa55aa; - free(alloc); -} - -void *crypt_safe_realloc(void *data, size_t size) -{ - struct safe_allocation *alloc; - void *new_data; - - new_data = crypt_safe_alloc(size); - - if (new_data && data) { - - alloc = (struct safe_allocation *) - ((char *)data - offsetof(struct safe_allocation, data)); - - if (size > alloc->size) - size = alloc->size; - - memcpy(new_data, data, size); - } - - crypt_safe_free(data); - return new_data; -} - ssize_t crypt_hex_to_bytes(const char *hex, char **result, int safe_alloc) { char buf[3] = "xx\0", *endp, *bytes; diff --git a/lib/utils_crypt.h b/lib/utils_crypt.h index 239805d5..9aa9b093 100644 --- a/lib/utils_crypt.h +++ b/lib/utils_crypt.h @@ -29,14 +29,6 @@ #define MAX_CIPHER_LEN_STR "31" #define MAX_KEYFILES 32 -struct crypt_device; - -/* Not to be used directly */ -struct safe_allocation { - size_t size; - char data[0]; -}; - int crypt_parse_name_and_mode(const char *s, char *cipher, int *key_nums, char *cipher_mode); int crypt_parse_hash_integrity_mode(const char *s, char *integrity); @@ -44,12 +36,6 @@ int crypt_parse_integrity_mode(const char *s, char *integrity, int *integrity_key_size); int crypt_parse_pbkdf(const char *s, const char **pbkdf); -void *crypt_safe_alloc(size_t size); -void crypt_safe_free(void *data); -void *crypt_safe_realloc(void *data, size_t size); - -void crypt_memzero(void *s, size_t n); - ssize_t crypt_hex_to_bytes(const char *hex, char **result, int safe_alloc); #endif /* _UTILS_CRYPT_H */ diff --git a/lib/utils_device.c b/lib/utils_device.c index 9b82a2d8..deb11e16 100644 --- a/lib/utils_device.c +++ b/lib/utils_device.c @@ -145,7 +145,7 @@ static int device_read_test(int devfd) if (read_blockwise(devfd, blocksize, alignment, buffer, minsize) == (ssize_t)minsize) r = 0; - crypt_memzero(buffer, sizeof(buffer)); + crypt_safe_memzero(buffer, sizeof(buffer)); return r; } diff --git a/lib/utils_keyring.c b/lib/utils_keyring.c index 2ad6ba4b..c7de21b8 100644 --- a/lib/utils_keyring.c +++ b/lib/utils_keyring.c @@ -25,15 +25,14 @@ #include #include +#include "libcryptsetup.h" +#include "utils_keyring.h" + #ifndef HAVE_KEY_SERIAL_T #define HAVE_KEY_SERIAL_T -#include typedef int32_t key_serial_t; #endif -#include "utils_crypt.h" -#include "utils_keyring.h" - #ifndef ARRAY_SIZE # define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) #endif @@ -178,7 +177,7 @@ int keyring_get_passphrase(const char *key_desc, if (ret < 0) { err = errno; if (buf) - crypt_memzero(buf, len); + crypt_safe_memzero(buf, len); free(buf); return -err; } diff --git a/lib/utils_safe_memory.c b/lib/utils_safe_memory.c new file mode 100644 index 00000000..89f0f49d --- /dev/null +++ b/lib/utils_safe_memory.c @@ -0,0 +1,102 @@ +/* + * utils_safe_memory - safe memory helpers + * + * Copyright (C) 2009-2019 Red Hat, Inc. All rights reserved. + * Copyright (C) 2009-2019 Milan Broz + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#include +#include +#include "libcryptsetup.h" + +struct safe_allocation { + size_t size; + char data[0]; +}; + +/* + * Replacement for memset(s, 0, n) on stack that can be optimized out + * Also used in safe allocations for explicit memory wipe. + */ +void crypt_safe_memzero(void *data, size_t size) +{ +#ifdef HAVE_EXPLICIT_BZERO + explicit_bzero(data, size); +#else + volatile uint8_t *p = (volatile uint8_t *)data; + + while(size--) + *p++ = 0; +#endif +} + +/* safe allocations */ +void *crypt_safe_alloc(size_t size) +{ + struct safe_allocation *alloc; + + if (!size || size > (SIZE_MAX - offsetof(struct safe_allocation, data))) + return NULL; + + alloc = malloc(size + offsetof(struct safe_allocation, data)); + if (!alloc) + return NULL; + + alloc->size = size; + crypt_safe_memzero(&alloc->data, size); + + /* coverity[leaked_storage] */ + return &alloc->data; +} + +void crypt_safe_free(void *data) +{ + struct safe_allocation *alloc; + + if (!data) + return; + + alloc = (struct safe_allocation *) + ((char *)data - offsetof(struct safe_allocation, data)); + + crypt_safe_memzero(data, alloc->size); + + alloc->size = 0x55aa55aa; + free(alloc); +} + +void *crypt_safe_realloc(void *data, size_t size) +{ + struct safe_allocation *alloc; + void *new_data; + + new_data = crypt_safe_alloc(size); + + if (new_data && data) { + + alloc = (struct safe_allocation *) + ((char *)data - offsetof(struct safe_allocation, data)); + + if (size > alloc->size) + size = alloc->size; + + memcpy(new_data, data, size); + } + + crypt_safe_free(data); + return new_data; +} diff --git a/lib/volumekey.c b/lib/volumekey.c index 266b8050..259c8bd1 100644 --- a/lib/volumekey.c +++ b/lib/volumekey.c @@ -47,7 +47,7 @@ struct volume_key *crypt_alloc_volume_key(size_t keylength, const char *key) if (key) memcpy(&vk->key, key, keylength); else - crypt_memzero(&vk->key, keylength); + crypt_safe_memzero(&vk->key, keylength); } return vk; @@ -120,7 +120,7 @@ void crypt_free_volume_key(struct volume_key *vk) struct volume_key *vk_next; while (vk) { - crypt_memzero(vk->key, vk->keylength); + crypt_safe_memzero(vk->key, vk->keylength); vk->keylength = 0; free(CONST_CAST(void*)vk->key_description); vk_next = vk->next; diff --git a/src/cryptsetup.c b/src/cryptsetup.c index 70219da2..92a0a200 100644 --- a/src/cryptsetup.c +++ b/src/cryptsetup.c @@ -448,7 +448,7 @@ static int tcrypt_load(struct crypt_device *cd, struct crypt_params_tcrypt *para continue; params->veracrypt_pim = (uint32_t)tmp_pim_ull; - crypt_memzero(&tmp_pim_ull, sizeof(tmp_pim_ull)); + crypt_safe_memzero(&tmp_pim_ull, sizeof(tmp_pim_ull)); } if (opt_tcrypt_hidden) @@ -512,7 +512,7 @@ static int action_open_tcrypt(void) out: crypt_free(cd); crypt_safe_free(CONST_CAST(char*)params.passphrase); - crypt_memzero(¶ms.veracrypt_pim, sizeof(params.veracrypt_pim)); + crypt_safe_memzero(¶ms.veracrypt_pim, sizeof(params.veracrypt_pim)); return r; }