diff options
Diffstat (limited to 'comm/third_party/libotr/src/mem.c')
-rw-r--r-- | comm/third_party/libotr/src/mem.c | 180 |
1 files changed, 180 insertions, 0 deletions
diff --git a/comm/third_party/libotr/src/mem.c b/comm/third_party/libotr/src/mem.c new file mode 100644 index 0000000000..29330ae757 --- /dev/null +++ b/comm/third_party/libotr/src/mem.c @@ -0,0 +1,180 @@ +/* + * Off-the-Record Messaging library + * Copyright (C) 2004-2014 Ian Goldberg, David Goulet, Rob Smits, + * Chris Alexander, Willy Lew, Lisa Du, + * Nikita Borisov + * <otr@cypherpunks.ca> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of version 2.1 of the GNU Lesser General + * Public License as published by the Free Software Foundation. + * + * This library 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/* Memory allocation routines for libgcrypt. All of the session key + * information gets allocated through here, so we can wipe it out when + * it's free()d. We don't use the built-in secmem functions of + * libgcrypt because you need to declare a fixed amount of it when you + * start up. + * + * Because "secure" and "insecure" allocations from libgcrypt will get + * handled the same way (since we're not going to be running as root, + * and so won't actually have pinned memory), pretend all allocated + * memory (but just from libgcrypt) is requested secure, and wipe it on + * free(). */ + +/* Uncomment the following to add a check that our free() and realloc() only + * get called on things returned from our malloc(). */ +/* #define OTRL_MEM_MAGIC 0x31415926 */ + +/* system headers */ +#ifdef OTRL_MEM_MAGIC +#include <stdio.h> +#endif +#include <stdlib.h> + +/* libgcrypt headers */ +#include <gcrypt.h> + +/* libotr headers */ +#include "mem.h" + +static size_t header_size; + +static void *otrl_mem_malloc(size_t n) +{ + void *p; + size_t new_n = n; + new_n += header_size; + + /* Check for overflow attack */ + if (new_n < n) return NULL; + p = malloc(new_n); + if (p == NULL) return NULL; + + ((size_t *)p)[0] = new_n; /* Includes header size */ +#ifdef OTRL_MEM_MAGIC + ((size_t *)p)[1] = OTRL_MEM_MAGIC; +#endif + + return (void *)((char *)p + header_size); +} + +static int otrl_mem_is_secure(const void *p) +{ + return 1; +} + +static void otrl_mem_free(void *p) +{ + void *real_p = (void *)((char *)p - header_size); + size_t n = ((size_t *)real_p)[0]; +#ifdef OTRL_MEM_MAGIC + if (((size_t *)real_p)[1] != OTRL_MEM_MAGIC) { + fprintf(stderr, "Illegal free!\n"); + return; + } +#endif + + /* Wipe the memory (in the same way the built-in deallocator in + * libgcrypt would) */ + memset(real_p, 0xff, n); + memset(real_p, 0xaa, n); + memset(real_p, 0x55, n); + memset(real_p, 0x00, n); + + free(real_p); +} + +static void *otrl_mem_realloc(void *p, size_t n) +{ + if (p == NULL) { + return otrl_mem_malloc(n); + } else if (n == 0) { + otrl_mem_free(p); + return NULL; + } else { + void *real_p = (void *)((char *)p - header_size); + void *new_p; + size_t old_n = ((size_t *)real_p)[0]; +#ifdef OTRL_MEM_MAGIC + size_t magic = ((size_t *)real_p)[1]; +#endif + size_t new_n = n; + new_n += header_size; + + /* Check for overflow attack */ + if (new_n < n) return NULL; + +#ifdef OTRL_MEM_MAGIC + if (magic != OTRL_MEM_MAGIC) { + fprintf(stderr, "Illegal realloc!\n"); + return NULL; + } +#endif + + if (new_n < old_n) { + /* Overwrite the space we're about to stop using */ + void *p = (void *)((char *)real_p + new_n); + size_t excess = old_n - new_n; + memset(p, 0xff, excess); + memset(p, 0xaa, excess); + memset(p, 0x55, excess); + memset(p, 0x00, excess); + + /* We don't actually need to realloc() */ + new_p = real_p; + } else { + new_p = realloc(real_p, new_n); + if (new_p == NULL) return NULL; + } + + ((size_t *)new_p)[0] = new_n; /* Includes header size */ + return (void *)((char *)new_p + header_size); + } +} + +void otrl_mem_init(void) +{ + header_size = 8; +#ifdef OTRL_MEM_MAGIC + if (header_size < 2*sizeof(size_t)) { + header_size = 2*sizeof(size_t); + } +#else + if (header_size < sizeof(size_t)) { + header_size = sizeof(size_t); + } +#endif + + gcry_set_allocation_handler( + otrl_mem_malloc, + otrl_mem_malloc, + otrl_mem_is_secure, + otrl_mem_realloc, + otrl_mem_free + ); +} + +/* Compare two memory blocks in time dependent on the length of the + * blocks, but not their contents. Returns 1 if they differ, 0 if they + * are the same. */ +int otrl_mem_differ(const unsigned char *buf1, const unsigned char *buf2, + size_t len) +{ + volatile unsigned char diff = 0; + size_t i; + + for (i = 0; i < len; ++i) { + diff |= (buf1[i] ^ buf2[i]); + } + return (diff != 0); +} |