Permalink
Browse files

make memory deallocation less lazy; ...

 * Make memory deallocation less lazy by cleaning up as much as possible
   on both normal and error paths. There is no strict requirement to do
   this as the memory will be properly cleaned up eventually anyway, but
   it does reduce the memory footprint.

 * Add first part of the backup header logic. Now backup headers are
   generated on volume creation, but not yet written.
  • Loading branch information...
1 parent 92f96b8 commit 8e1782ad8455247b8ec5fefc0ea67c90c2e23b99 @bwalex committed Jul 22, 2011
Showing with 236 additions and 59 deletions.
  1. +29 −2 crypto.c
  2. +74 −11 hdr.c
  3. +2 −1 io.c
  4. +128 −44 tcplay.c
  5. +3 −1 tcplay.h
View
31 crypto.c
@@ -89,12 +89,28 @@ tc_cipher_chain_populate_keys(struct tc_cipher_chain *cipher_chain,
}
int
+tc_cipher_chain_free_keys(struct tc_cipher_chain *cipher_chain)
+{
+ for (; cipher_chain != NULL; cipher_chain = cipher_chain->next) {
+ if (cipher_chain->key != NULL) {
+ free_safe_mem(cipher_chain->key);
+ cipher_chain->key = NULL;
+ }
+ }
+
+ return 0;
+}
+
+int
tc_encrypt(struct tc_cipher_chain *cipher_chain, unsigned char *key,
unsigned char *iv,
unsigned char *in, int in_len, unsigned char *out)
{
+ struct tc_cipher_chain *chain_start;
int err;
+ chain_start = cipher_chain;
+
if ((err = tc_cipher_chain_populate_keys(cipher_chain, key)))
return err;
@@ -119,13 +135,17 @@ tc_encrypt(struct tc_cipher_chain *cipher_chain, unsigned char *key,
/* Deallocate this key, since we won't need it anymore */
free_safe_mem(cipher_chain->key);
- if (err != 0)
+ if (err != 0) {
+ tc_cipher_chain_free_keys(chain_start);
return err;
+ }
/* Set next input buffer as current output buffer */
in = out;
}
+ tc_cipher_chain_free_keys(chain_start);
+
return 0;
}
@@ -134,8 +154,11 @@ tc_decrypt(struct tc_cipher_chain *cipher_chain, unsigned char *key,
unsigned char *iv,
unsigned char *in, int in_len, unsigned char *out)
{
+ struct tc_cipher_chain *chain_start;
int err;
+ chain_start = cipher_chain;
+
if ((err = tc_cipher_chain_populate_keys(cipher_chain, key)))
return err;
@@ -163,13 +186,17 @@ tc_decrypt(struct tc_cipher_chain *cipher_chain, unsigned char *key,
/* Deallocate this key, since we won't need it anymore */
free_safe_mem(cipher_chain->key);
- if (err != 0)
+ if (err != 0) {
+ tc_cipher_chain_free_keys(chain_start);
return err;
+ }
/* Set next input buffer as current output buffer */
in = out;
}
+ tc_cipher_chain_free_keys(chain_start);
+
return 0;
}
View
85 hdr.c
@@ -128,47 +128,79 @@ struct tchdr_enc *
create_hdr(unsigned char *pass, int passlen, struct pbkdf_prf_algo *prf_algo,
struct tc_cipher_chain *cipher_chain, size_t sec_sz,
size_t total_blocks __unused,
- off_t offset, size_t blocks, int hidden)
+ off_t offset, size_t blocks, int hidden, struct tchdr_enc **backup_hdr)
{
- struct tchdr_enc *ehdr;
+ struct tchdr_enc *ehdr, *ehdr_backup;
struct tchdr_dec *dhdr;
- unsigned char *key;
+ unsigned char *key, *key_backup;
unsigned char iv[128];
int error;
+ key = key_backup = NULL;
+ dhdr = NULL;
+ ehdr = ehdr_backup = NULL;
+
+ if (backup_hdr != NULL)
+ *backup_hdr = NULL;
+
if ((dhdr = (struct tchdr_dec *)alloc_safe_mem(sizeof(*dhdr))) == NULL) {
tc_log(1, "could not allocate safe dhdr memory\n");
- return NULL;
+ goto error;
}
if ((ehdr = (struct tchdr_enc *)alloc_safe_mem(sizeof(*ehdr))) == NULL) {
tc_log(1, "could not allocate safe ehdr memory\n");
- return NULL;
+ goto error;
+ }
+
+ if ((ehdr_backup = (struct tchdr_enc *)alloc_safe_mem
+ (sizeof(*ehdr_backup))) == NULL) {
+ tc_log(1, "could not allocate safe ehdr_backup memory\n");
+ goto error;
}
if ((key = alloc_safe_mem(MAX_KEYSZ)) == NULL) {
tc_log(1, "could not allocate safe key memory\n");
- return NULL;
+ goto error;
+ }
+
+ if ((key_backup = alloc_safe_mem(MAX_KEYSZ)) == NULL) {
+ tc_log(1, "could not allocate safe backup key memory\n");
+ goto error;
}
if ((error = get_random(ehdr->salt, sizeof(ehdr->salt))) != 0) {
tc_log(1, "could not get salt\n");
- return NULL;
+ goto error;
+ }
+
+ if ((error = get_random(ehdr_backup->salt, sizeof(ehdr_backup->salt)))
+ != 0) {
+ tc_log(1, "could not get salt for backup header\n");
+ goto error;
}
error = pbkdf2(prf_algo, (char *)pass, passlen,
ehdr->salt, sizeof(ehdr->salt),
MAX_KEYSZ, key);
if (error) {
tc_log(1, "could not derive key\n");
- return NULL;
+ goto error;
+ }
+
+ error = pbkdf2(prf_algo, (char *)pass, passlen,
+ ehdr_backup->salt, sizeof(ehdr_backup->salt),
+ MAX_KEYSZ, key_backup);
+ if (error) {
+ tc_log(1, "could not derive backup key\n");
+ goto error;
}
memset(dhdr, 0, sizeof(*dhdr));
if ((error = get_random(dhdr->keys, sizeof(dhdr->keys))) != 0) {
tc_log(1, "could not get key random bits\n");
- return NULL;
+ goto error;
}
memcpy(dhdr->tc_str, "TRUE", 4);
@@ -201,10 +233,41 @@ create_hdr(unsigned char *pass, int passlen, struct pbkdf_prf_algo *prf_algo,
sizeof(struct tchdr_dec), ehdr->enc);
if (error) {
tc_log(1, "Header encryption failed\n");
- free_safe_mem(dhdr);
- return NULL;
+ goto error;
+ }
+
+ memset(iv, 0, sizeof(iv));
+ error = tc_encrypt(cipher_chain, key_backup, iv,
+ (unsigned char *)dhdr,
+ sizeof(struct tchdr_dec), ehdr_backup->enc);
+ if (error) {
+ tc_log(1, "Backup header encryption failed\n");
+ goto error;
}
+ free_safe_mem(key);
+ free_safe_mem(key_backup);
free_safe_mem(dhdr);
+
+ if (backup_hdr != NULL)
+ *backup_hdr = ehdr_backup;
+ else
+ free_safe_mem(ehdr_backup);
+
return ehdr;
+ /* NOT REACHED */
+
+error:
+ if (key)
+ free_safe_mem(key);
+ if (key_backup)
+ free_safe_mem(key_backup);
+ if (dhdr)
+ free_safe_mem(dhdr);
+ if (ehdr)
+ free_safe_mem(ehdr);
+ if (ehdr_backup)
+ free_safe_mem(ehdr_backup);
+
+ return NULL;
}
View
3 io.c
@@ -126,7 +126,8 @@ get_random(unsigned char *buf, size_t len)
sz = (len - rd);
if ((r = read(fd, buf+rd, sz)) < 0) {
- tc_log(1, "Error reading from /dev/random\n");
+ tc_log(1, "Error reading from /dev/random(%d): %s\n",
+ fd, strerror(errno));
close(fd);
summary_fn = NULL;
return -1;
View
172 tcplay.c
@@ -240,10 +240,13 @@ struct tcplay_info *
new_info(const char *dev, struct tc_cipher_chain *cipher_chain,
struct pbkdf_prf_algo *prf, struct tchdr_dec *hdr, off_t start)
{
+ struct tc_cipher_chain *chain_start;
struct tcplay_info *info;
int i;
int error;
+ chain_start = cipher_chain;
+
if ((info = (struct tcplay_info *)alloc_safe_mem(sizeof(*info))) == NULL) {
tc_log(1, "could not allocate safe info memory\n");
return NULL;
@@ -271,6 +274,8 @@ new_info(const char *dev, struct tc_cipher_chain *cipher_chain,
cipher_chain->key[i]);
}
+ tc_cipher_chain_free_keys(chain_start);
+
return info;
}
@@ -316,6 +321,7 @@ process_hdr(const char *dev, unsigned char *pass, int passlen,
if (error) {
tc_log(1, "pbkdf failed for algorithm %s\n",
pbkdf_prf_algos[i].name);
+ free_safe_mem(key);
return EINVAL;
}
@@ -333,6 +339,7 @@ process_hdr(const char *dev, unsigned char *pass, int passlen,
if (dhdr == NULL) {
tc_log(1, "hdr decryption failed for cipher "
"chain %d\n", j);
+ free_safe_mem(key);
return EINVAL;
}
@@ -361,10 +368,15 @@ process_hdr(const char *dev, unsigned char *pass, int passlen,
if ((info = new_info(dev, tc_cipher_chains[j-1], &pbkdf_prf_algos[i-1],
dhdr, 0)) == NULL) {
+ free_safe_mem(dhdr);
return ENOMEM;
}
+ if (dhdr)
+ free_safe_mem(dhdr);
+
*pinfo = info;
+
return 0;
}
@@ -379,9 +391,15 @@ create_volume(const char *dev, int hidden, const char *keyfiles[], int nkeyfiles
char *h_pass = NULL;
char buf[1024];
size_t blocks, blksz, hidden_blocks = 0;
- struct tchdr_enc *ehdr, *hehdr = NULL;
+ struct tchdr_enc *ehdr, *hehdr;
+ struct tchdr_enc *ehdr_backup, *hehdr_backup;
uint64_t tmp;
- int error, r;
+ int error, r, ret;
+
+ pass = h_pass = pass_again = NULL;
+ ehdr = hehdr = NULL;
+ ehdr_backup = hehdr_backup = NULL;
+ ret = -1; /* Default to returning error */
if (cipher_chain == NULL)
cipher_chain = tc_cipher_chains[0];
@@ -407,28 +425,29 @@ create_volume(const char *dev, int hidden, const char *keyfiles[], int nkeyfiles
if (((pass = alloc_safe_mem(MAX_PASSSZ)) == NULL) ||
((pass_again = alloc_safe_mem(MAX_PASSSZ)) == NULL)) {
tc_log(1, "could not allocate safe passphrase memory\n");
- return -1;
+ goto out;
}
if ((error = read_passphrase("Passphrase: ", pass, MAX_PASSSZ, 0) ||
(read_passphrase("Repeat passphrase: ", pass_again,
MAX_PASSSZ, 0)))) {
tc_log(1, "could not read passphrase\n");
- return -1;
+ goto out;
}
if (strcmp(pass, pass_again) != 0) {
tc_log(1, "Passphrases don't match\n");
- return -1;
+ goto out;
}
free_safe_mem(pass_again);
+ pass_again = NULL;
} else {
/* In batch mode, use provided passphrase */
if ((pass = alloc_safe_mem(MAX_PASSSZ)) == NULL) {
tc_log(1, "could not allocate safe "
"passphrase memory");
- return -1;
+ goto out;
}
if (passphrase != NULL)
@@ -440,6 +459,7 @@ create_volume(const char *dev, int hidden, const char *keyfiles[], int nkeyfiles
if ((error = apply_keyfiles((unsigned char *)pass, MAX_PASSSZ,
keyfiles, nkeyfiles))) {
tc_log(1, "could not apply keyfiles\n");
+ goto out;
}
}
@@ -449,30 +469,31 @@ create_volume(const char *dev, int hidden, const char *keyfiles[], int nkeyfiles
((pass_again = alloc_safe_mem(MAX_PASSSZ)) == NULL)) {
tc_log(1, "could not allocate safe "
"passphrase memory\n");
- return -1;
+ goto out;
}
if ((error = read_passphrase("Passphrase for hidden volume: ",
h_pass, MAX_PASSSZ, 0) ||
(read_passphrase("Repeat passphrase: ", pass_again,
MAX_PASSSZ, 0)))) {
tc_log(1, "could not read passphrase\n");
- return -1;
+ goto out;
}
if (strcmp(h_pass, pass_again) != 0) {
tc_log(1, "Passphrases for hidden volume don't "
"match\n");
- return -1;
+ goto out;
}
free_safe_mem(pass_again);
+ pass_again = NULL;
} else {
/* In batch mode, use provided passphrase */
if ((h_pass = alloc_safe_mem(MAX_PASSSZ)) == NULL) {
tc_log(1, "could not allocate safe "
"passphrase memory");
- return -1;
+ goto out;
}
if (h_passphrase != NULL)
@@ -484,7 +505,7 @@ create_volume(const char *dev, int hidden, const char *keyfiles[], int nkeyfiles
if ((error = apply_keyfiles((unsigned char *)h_pass,
MAX_PASSSZ, h_keyfiles, n_hkeyfiles))) {
tc_log(1, "could not apply keyfiles\n");
- return -1;
+ goto out;
}
}
@@ -495,14 +516,14 @@ create_volume(const char *dev, int hidden, const char *keyfiles[], int nkeyfiles
if (hidden_blocks == 0) {
tc_log(1, "hidden_blocks to create volume "
"cannot be zero!\n");
- return -1;
+ goto out;
}
if (size_hidden_bytes_in >=
(blocks*blksz) - MIN_VOL_BYTES) {
tc_log(1, "Hidden volume needs to be "
"smaller than the outer volume\n");
- return -1;
+ goto out;
}
}
@@ -520,15 +541,15 @@ create_volume(const char *dev, int hidden, const char *keyfiles[], int nkeyfiles
if ((fgets(buf, sizeof(buf), stdin)) == NULL) {
tc_log(1, "Could not read from stdin\n");
- return -1;
+ goto out;
}
/* get rid of trailing newline */
buf[strlen(buf)-1] = '\0';
if ((error = _dehumanize_number(buf,
&tmp)) != 0) {
tc_log(1, "Could not interpret input: %s\n", buf);
- return -1;
+ continue;
}
if (tmp >= (blocks*blksz) - MIN_VOL_BYTES) {
@@ -558,29 +579,29 @@ create_volume(const char *dev, int hidden, const char *keyfiles[], int nkeyfiles
fflush(stdout);
if ((fgets(buf, sizeof(buf), stdin)) == NULL) {
tc_log(1, "Could not read from stdin\n");
- return -1;
+ goto out;
}
if ((buf[0] != 'y') && (buf[0] != 'Y')) {
tc_log(1, "User cancelled action(s)\n");
- return -1;
+ goto out;
}
}
/* erase volume */
if ((error = secure_erase(dev, blocks * blksz, blksz)) != 0) {
tc_log(1, "could not securely erase device %s\n", dev);
- return -1;
+ goto out;
}
/* create encrypted headers */
ehdr = create_hdr((unsigned char *)pass,
(nkeyfiles > 0)?MAX_PASSSZ:strlen(pass),
prf_algo, cipher_chain, blksz, blocks, VOL_RSVD_BYTES_START/blksz,
- blocks - (MIN_VOL_BYTES/blksz), 0);
+ blocks - (MIN_VOL_BYTES/blksz), 0, &ehdr_backup);
if (ehdr == NULL) {
tc_log(1, "Could not create header\n");
- return -1;
+ goto out;
}
if (hidden) {
@@ -589,28 +610,49 @@ create_volume(const char *dev, int hidden, const char *keyfiles[], int nkeyfiles
h_cipher_chain,
blksz, blocks,
blocks - (VOL_RSVD_BYTES_END/blksz) - hidden_blocks,
- hidden_blocks, 1);
+ hidden_blocks, 1, &hehdr_backup);
if (hehdr == NULL) {
tc_log(1, "Could not create hidden volume header\n");
- return -1;
+ goto out;
}
}
if ((error = write_to_disk(dev, 0, blksz, ehdr, sizeof(*ehdr))) != 0) {
tc_log(1, "Could not write volume header to device\n");
- return -1;
+ goto out;
}
+ /* XXX: write backup header */
if (hidden) {
if ((error = write_to_disk(dev, HDR_OFFSET_HIDDEN, blksz, hehdr,
sizeof(*hehdr))) != 0) {
tc_log(1, "Could not write hidden volume header to "
"device\n");
- return -1;
+ goto out;
}
+ /* XXX: write backup header */
}
- return 0;
+ /* Everything went ok */
+ ret = 0;
+
+out:
+ if (pass)
+ free_safe_mem(pass);
+ if (h_pass)
+ free_safe_mem(h_pass);
+ if (pass_again)
+ free_safe_mem(pass_again);
+ if (ehdr)
+ free_safe_mem(ehdr);
+ if (hehdr)
+ free_safe_mem(hehdr);
+ if (ehdr_backup)
+ free_safe_mem(ehdr_backup);
+ if (hehdr_backup)
+ free_safe_mem(hehdr_backup);
+
+ return ret;
}
static
@@ -633,26 +675,28 @@ info_map_common(const char *dev, int sflag, const char *sys_dev,
return NULL;
}
- info = NULL;
if (retries < 1)
retries = 1;
+ info = NULL;
+
while ((info == NULL) && retries-- > 0)
{
- h_pass = NULL;
- ehdr = NULL;
- hehdr = NULL;
+ pass = h_pass = NULL;
+ ehdr = hehdr = NULL;
+ info = hinfo = NULL;
if ((pass = alloc_safe_mem(MAX_PASSSZ)) == NULL) {
tc_log(1, "could not allocate safe passphrase memory\n");
- return NULL;
+ goto out;
}
if (interactive) {
if ((error = read_passphrase("Passphrase: ", pass,
MAX_PASSSZ, timeout))) {
tc_log(1, "could not read passphrase\n");
- return NULL;
+ /* XXX: handle timeout differently? */
+ goto out;
}
} else {
/* In batch mode, use provided passphrase */
@@ -665,22 +709,22 @@ info_map_common(const char *dev, int sflag, const char *sys_dev,
if ((error = apply_keyfiles((unsigned char *)pass, MAX_PASSSZ,
keyfiles, nkeyfiles))) {
tc_log(1, "could not apply keyfiles");
- return NULL;
+ goto out;
}
}
if (protect_hidden) {
if ((h_pass = alloc_safe_mem(MAX_PASSSZ)) == NULL) {
tc_log(1, "could not allocate safe passphrase memory\n");
- return NULL;
+ goto out;
}
if (interactive) {
if ((error = read_passphrase(
"Passphrase for hidden volume: ", h_pass,
MAX_PASSSZ, timeout))) {
tc_log(1, "could not read passphrase\n");
- return NULL;
+ goto out;
}
} else {
/* In batch mode, use provided passphrase */
@@ -693,7 +737,7 @@ info_map_common(const char *dev, int sflag, const char *sys_dev,
if ((error = apply_keyfiles((unsigned char *)h_pass, MAX_PASSSZ,
h_keyfiles, n_hkeyfiles))) {
tc_log(1, "could not apply keyfiles");
- return NULL;
+ goto out;
}
}
}
@@ -705,7 +749,7 @@ info_map_common(const char *dev, int sflag, const char *sys_dev,
(sflag) ? HDR_OFFSET_SYS : 0, &sz);
if (ehdr == NULL) {
tc_log(1, "error read hdr_enc: %s", dev);
- return NULL;
+ goto out;
}
if (!sflag) {
@@ -716,7 +760,7 @@ info_map_common(const char *dev, int sflag, const char *sys_dev,
HDR_OFFSET_HIDDEN, &sz);
if (hehdr == NULL) {
tc_log(1, "error read hdr_enc: %s", dev);
- return NULL;
+ goto out;
}
} else {
hehdr = NULL;
@@ -747,28 +791,61 @@ info_map_common(const char *dev, int sflag, const char *sys_dev,
if ((protect_hidden && (error || error2)) ||
(error && error2)) {
tc_log(1, "Incorrect password or not a TrueCrypt volume\n");
- info = NULL;
- hinfo = NULL;
+
+ if (info) {
+ free_safe_mem(info);
+ info = NULL;
+ }
+ if (hinfo) {
+ free_safe_mem(hinfo);
+ hinfo = NULL;
+ }
/* Try again (or finish) */
free_safe_mem(pass);
- if (h_pass)
+ pass = NULL;
+
+ if (h_pass) {
free_safe_mem(h_pass);
- if (ehdr)
+ h_pass = NULL;
+ }
+ if (ehdr) {
free_safe_mem(ehdr);
- if (hehdr)
+ ehdr = NULL;
+ }
+ if (hehdr) {
free_safe_mem(hehdr);
+ hehdr = NULL;
+ }
continue;
}
if (protect_hidden) {
if (adjust_info(info, hinfo) != 0) {
tc_log(1, "Could not protect hidden volume\n");
- return NULL;
+ if (info)
+ free_safe_mem(info);
+ info = NULL;
+ free_safe_mem(hinfo);
+ hinfo = NULL;
+ goto out;
}
+ free_safe_mem(hinfo);
}
}
+out:
+ if (hinfo)
+ free_safe_mem(hinfo);
+ if (pass)
+ free_safe_mem(pass);
+ if (h_pass)
+ free_safe_mem(h_pass);
+ if (ehdr)
+ free_safe_mem(ehdr);
+ if (hehdr)
+ free_safe_mem(hehdr);
+
return info;
}
@@ -788,9 +865,13 @@ info_volume(const char *device, int sflag, const char *sys_dev,
if (info != NULL) {
if (interactive)
print_info(info);
+ free_safe_mem(info);
+
+ return 0;
+ /* NOT REACHED */
}
- return (info != NULL) ? 0 : -1;
+ return -1;
}
int
@@ -813,12 +894,15 @@ map_volume(const char *map_name, const char *device, int sflag,
if ((error = dm_setup(map_name, info)) != 0) {
tc_log(1, "Could not set up mapping %s\n", map_name);
+ free_safe_mem(info);
return -1;
}
if (interactive)
printf("All ok!\n");
+ free_safe_mem(info);
+
return 0;
}
View
4 tcplay.h
@@ -146,6 +146,7 @@ int read_passphrase(const char *prompt, char *pass, size_t passlen,
int tc_crypto_init(void);
int tc_cipher_chain_populate_keys(struct tc_cipher_chain *cipher_chain,
unsigned char *key);
+int tc_cipher_chain_free_keys(struct tc_cipher_chain *cipher_chain);
int tc_encrypt(struct tc_cipher_chain *cipher_chain, unsigned char *key,
unsigned char *iv,
unsigned char *in, int in_len, unsigned char *out);
@@ -167,7 +168,8 @@ int apply_keyfiles(unsigned char *pass, size_t pass_memsz, const char *keyfiles[
struct tchdr_enc *create_hdr(unsigned char *pass, int passlen,
struct pbkdf_prf_algo *prf_algo, struct tc_cipher_chain *cipher_chain,
size_t sec_sz, size_t total_blocks,
- off_t offset, size_t blocks, int hidden);
+ off_t offset, size_t blocks, int hidden,
+ struct tchdr_enc **backup_hdr);
struct tchdr_dec *decrypt_hdr(struct tchdr_enc *ehdr,
struct tc_cipher_chain *cipher_chain, unsigned char *key);
int verify_hdr(struct tchdr_dec *hdr);

0 comments on commit 8e1782a

Please sign in to comment.