diff options
author | Werner Koch <wk@gnupg.org> | 2000-01-24 11:55:48 +0000 |
---|---|---|
committer | Werner Koch <wk@gnupg.org> | 2000-01-24 11:55:48 +0000 |
commit | 57eb8c1b9d58df4cc3e026f82244f2928c008e2b (patch) | |
tree | bf97f3b0795a1a10de60ae08255e67d9e578b2c5 /src | |
parent | d5bd6cb82646a4d52870b23d21262c83de77ae47 (diff) | |
download | libgcrypt-57eb8c1b9d58df4cc3e026f82244f2928c008e2b.tar.gz |
See ChangeLog: Mon Jan 24 13:04:28 CET 2000 Werner Koch
Diffstat (limited to 'src')
-rw-r--r-- | src/ChangeLog | 7 | ||||
-rw-r--r-- | src/Makefile.am | 9 | ||||
-rw-r--r-- | src/gcrypt.h | 14 | ||||
-rw-r--r-- | src/global.c | 40 | ||||
-rw-r--r-- | src/mpi.h | 1 | ||||
-rw-r--r-- | src/secmem.c | 422 | ||||
-rw-r--r-- | src/secmem.h | 35 | ||||
-rw-r--r-- | src/sexp.c | 35 | ||||
-rw-r--r-- | src/stdmem.c | 186 | ||||
-rw-r--r-- | src/stdmem.h | 32 | ||||
-rw-r--r-- | src/wrapper.c | 3 |
11 files changed, 753 insertions, 31 deletions
diff --git a/src/ChangeLog b/src/ChangeLog index d59feab9..4c2a5b2f 100644 --- a/src/ChangeLog +++ b/src/ChangeLog @@ -1,3 +1,10 @@ +Mon Jan 24 13:04:28 CET 2000 Werner Koch <wk@gnupg.de> + + * secmem.c: Moved from ../util to here. + * secmem.h: New. + * stdmem.c: New. Based on the old ../util/memory.c. + * stdmem.h: New. + Wed Dec 8 21:58:32 CET 1999 Werner Koch <wk@gnupg.de> * gcrypt.m4: New. diff --git a/src/Makefile.am b/src/Makefile.am index e88bba14..41174876 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -25,12 +25,15 @@ libgcrypt_la_SOURCES = mpi.h \ global.c \ sexp.c \ wrapper.c \ - memory.c \ - secmem.c + stdmem.c \ + stdmem.h \ + secmem.c \ + secmem.h libgcrypt_la_DEPENDENCIES = libgcrypt.sym libgcrypt_la_LIBADD = ../cipher/libcipher.la \ - ../mpi/libmpi.la + ../mpi/libmpi.la \ + ../jnlib/libjnlib.la BUILT_SOURCES = libgcrypt.sym diff --git a/src/gcrypt.h b/src/gcrypt.h index 46119181..63715d49 100644 --- a/src/gcrypt.h +++ b/src/gcrypt.h @@ -118,6 +118,14 @@ enum gcry_ctl_cmds { GCRYCTL_SET_DEBUG_FLAGS = 20, GCRYCTL_CLEAR_DEBUG_FLAGS = 21, GCRYCTL_USE_SECURE_RNDPOOL= 22, + GCRYCTL_DUMP_MEMORY_STATS = 23, + GCRYCTL_INIT_SECMEM = 24, + GCRYCTL_TERM_SECMEM = 25, + GCRYCTL_DISABLE_SECMEM_WARN = 27, + GCRYCTL_SUSPEND_SECMEM_WARN = 28, + GCRYCTL_RESUME_SECMEM_WARN = 29, + GCRYCTL_DROP_PRIVS = 30, + GCRYCTL_ENABLE_M_GUARD = 31, }; int gcry_control( enum gcry_ctl_cmds, ... ); @@ -210,6 +218,8 @@ int gcry_mpi_scan( GCRY_MPI *ret_mpi, enum gcry_mpi_format format, const char *buffer, size_t *nbytes ); int gcry_mpi_print( enum gcry_mpi_format format, char *buffer, size_t *nbytes, const GCRY_MPI a ); +int gcry_mpi_aprint( enum gcry_mpi_format format, + void **buffer, size_t *nbytes, const GCRY_MPI a ); void gcry_mpi_powm( GCRY_MPI w, const GCRY_MPI b, const GCRY_MPI e, const GCRY_MPI m ); @@ -324,6 +334,7 @@ int gcry_pk_ctl( int cmd, void *buffer, size_t buflen); int gcry_pk_algo_info( int algo, int what, void *buffer, size_t *nbytes); const char *gcry_pk_algo_name( int algo ); int gcry_pk_map_name( const char* name ); +unsigned int gcry_pk_get_nbits( GCRY_SEXP key ); #define gcry_pk_test_algo(a) \ @@ -444,7 +455,8 @@ void *gcry_xmalloc_secure( size_t n ); void *gcry_xcalloc_secure( size_t n, size_t m ); void *gcry_xrealloc( void *a, size_t n ); char *gcry_xstrdup( const char * a); -void gcry_free( void *p ); +void gcry_free( void *a ); +int gcry_is_secure( const void *a ); #ifndef GCRYPT_NO_MPI_MACROS diff --git a/src/global.c b/src/global.c index 1de2bd62..2e84f4b6 100644 --- a/src/global.c +++ b/src/global.c @@ -27,7 +27,8 @@ #include <assert.h> #include "g10lib.h" -#include "memory.h" /* for the m_* functions */ +#include "stdmem.h" /* our own memory allocator */ +#include "secmem.h" /* our own secmem allocator */ /**************** * flag bits: 0 : general cipher debug @@ -128,14 +129,47 @@ gcry_control( enum gcry_ctl_cmds cmd, ... ) case GCRYCTL_SET_FATAL_FNC: break; #endif + + case GCRYCTL_ENABLE_M_GUARD: + g10_private_enable_m_guard(); + break; + case GCRYCTL_DUMP_RANDOM_STATS: random_dump_stats(); break; + case GCRYCTL_DUMP_MEMORY_STATS: + /*m_print_stats("[fixme: prefix]");*/ + break; + case GCRYCTL_DUMP_SECMEM_STATS: secmem_dump_stats(); break; + case GCRYCTL_DROP_PRIVS: + secmem_init( 0 ); + break; + + case GCRYCTL_INIT_SECMEM: + secmem_init( va_arg( arg_ptr, unsigned int ) ); + break; + + case GCRYCTL_TERM_SECMEM: + secmem_term(); + break; + + case GCRYCTL_DISABLE_SECMEM_WARN: + secmem_set_flags( secmem_get_flags() | 1 ); + break; + + case GCRYCTL_SUSPEND_SECMEM_WARN: + secmem_set_flags( secmem_get_flags() | 2 ); + break; + + case GCRYCTL_RESUME_SECMEM_WARN: + secmem_set_flags( secmem_get_flags() & ~2 ); + break; + case GCRYCTL_USE_SECURE_RNDPOOL: secure_random_alloc(); /* put random number into secure memory */ break; @@ -234,11 +268,11 @@ gcry_set_allocation_handler( void *(*new_alloc_func)(size_t n), * ran out of memory. This handler may do one of these things: * o free some memory and return true, so that the xmalloc function * tries again. - * o Do whatever tit like and return false, so that the xmalloc functions + * o Do whatever it like and return false, so that the xmalloc functions * use the default fatal error handler. * o Terminate the program and don't return. * - * The handler function is called with 3 argiments: The opaque value set with + * The handler function is called with 3 arguments: The opaque value set with * this function, the requested memory size, and a flag with these bits * currently defined: * bit 0 set = secure memory has been requested. @@ -93,7 +93,6 @@ void mpi_swap( MPI a, MPI b); /*-- mpicoder.c --*/ int mpi_fromstr(MPI val, const char *str); -int mpi_print( FILE *fp, MPI a, int mode ); void g10_log_mpidump( const char *text, MPI a ); u32 mpi_get_keyid( MPI a, u32 *keyid ); byte *mpi_get_buffer( MPI a, unsigned *nbytes, int *sign ); diff --git a/src/secmem.c b/src/secmem.c new file mode 100644 index 00000000..7c27de00 --- /dev/null +++ b/src/secmem.c @@ -0,0 +1,422 @@ +/* secmem.c - memory allocation from a secure heap + * Copyright (C) 1998,1999 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG 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. + * + * GnuPG 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <stdarg.h> +#include <unistd.h> +#if defined(HAVE_MLOCK) || defined(HAVE_MMAP) + #include <sys/mman.h> + #include <sys/types.h> + #include <fcntl.h> + #ifdef USE_CAPABILITIES + #include <sys/capability.h> + #endif +#endif + +#include "types.h" +#include "secmem.h" +#include "util.h" +#include "i18n.h" + +#if defined(MAP_ANON) && !defined(MAP_ANONYMOUS) + #define MAP_ANONYMOUS MAP_ANON +#endif + +#define DEFAULT_POOLSIZE 16384 + +typedef struct memblock_struct MEMBLOCK; +struct memblock_struct { + unsigned size; + union { + MEMBLOCK *next; + PROPERLY_ALIGNED_TYPE aligned; + } u; +}; + + + +static void *pool; +static volatile int pool_okay; /* may be checked in an atexit function */ +static int pool_is_mmapped; +static size_t poolsize; /* allocated length */ +static size_t poollen; /* used length */ +static MEMBLOCK *unused_blocks; +static unsigned max_alloced; +static unsigned cur_alloced; +static unsigned max_blocks; +static unsigned cur_blocks; +static int disable_secmem; +static int show_warning; +static int no_warning; +static int suspend_warning; + + +static void +print_warn(void) +{ + if( !no_warning ) + log_info(_("Warning: using insecure memory!\n")); +} + + +static void +lock_pool( void *p, size_t n ) +{ + #if defined(USE_CAPABILITIES) && defined(HAVE_MLOCK) + int err; + + cap_set_proc( cap_from_text("cap_ipc_lock+ep") ); + err = mlock( p, n ); + if( err && errno ) + err = errno; + cap_set_proc( cap_from_text("cap_ipc_lock+p") ); + + if( err ) { + if( errno != EPERM + #ifdef EAGAIN /* OpenBSD returns this */ + && errno != EAGAIN + #endif + #ifdef ENOSYS /* Some SCOs return this (function not implemented) */ + && errno != ENOSYS + #endif + ) + log_error("can't lock memory: %s\n", strerror(err)); + show_warning = 1; + } + + #elif defined(HAVE_MLOCK) + uid_t uid; + int err; + + uid = getuid(); + + #ifdef HAVE_BROKEN_MLOCK + if( uid ) { + errno = EPERM; + err = errno; + } + else { + err = mlock( p, n ); + if( err && errno ) + err = errno; + } + #else + err = mlock( p, n ); + if( err && errno ) + err = errno; + #endif + + if( uid && !geteuid() ) { + if( setuid( uid ) || getuid() != geteuid() ) + log_fatal("failed to reset uid: %s\n", strerror(errno)); + } + + if( err ) { + if( errno != EPERM + #ifdef EAGAIN /* OpenBSD returns this */ + && errno != EAGAIN + #endif + #ifdef ENOSYS /* Some SCOs return this (function not implemented) */ + && errno != ENOSYS + #endif + ) + log_error("can't lock memory: %s\n", strerror(err)); + show_warning = 1; + } + + #else + log_info("Please note that you don't have secure memory on this system\n"); + #endif +} + + +static void +init_pool( size_t n) +{ + size_t pgsize; + + poolsize = n; + + if( disable_secmem ) + log_bug("secure memory is disabled"); + + #ifdef HAVE_GETPAGESIZE + pgsize = getpagesize(); + #else + pgsize = 4096; + #endif + + #if HAVE_MMAP + poolsize = (poolsize + pgsize -1 ) & ~(pgsize-1); + #ifdef MAP_ANONYMOUS + pool = mmap( 0, poolsize, PROT_READ|PROT_WRITE, + MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); + #else /* map /dev/zero instead */ + { int fd; + + fd = open("/dev/zero", O_RDWR); + if( fd == -1 ) { + log_error("can't open /dev/zero: %s\n", strerror(errno) ); + pool = (void*)-1; + } + else { + pool = mmap( 0, poolsize, PROT_READ|PROT_WRITE, + MAP_PRIVATE, fd, 0); + } + } + #endif + if( pool == (void*)-1 ) + log_info("can't mmap pool of %u bytes: %s - using malloc\n", + (unsigned)poolsize, strerror(errno)); + else { + pool_is_mmapped = 1; + pool_okay = 1; + } + + #endif + if( !pool_okay ) { + pool = malloc( poolsize ); + if( !pool ) + log_fatal("can't allocate memory pool of %u bytes\n", + (unsigned)poolsize); + else + pool_okay = 1; + } + lock_pool( pool, poolsize ); + poollen = 0; +} + + +/* concatenate unused blocks */ +static void +compress_pool(void) +{ + /* fixme: we really should do this */ +} + +void +secmem_set_flags( unsigned flags ) +{ + int was_susp = suspend_warning; + + no_warning = flags & 1; + suspend_warning = flags & 2; + + /* and now issue the warning if it is not longer suspended */ + if( was_susp && !suspend_warning && show_warning ) { + show_warning = 0; + print_warn(); + } +} + +unsigned +secmem_get_flags(void) +{ + unsigned flags; + + flags = no_warning ? 1:0; + flags |= suspend_warning ? 2:0; + return flags; +} + +void +secmem_init( size_t n ) +{ + if( !n ) { + #ifdef USE_CAPABILITIES + /* drop all capabilities */ + cap_set_proc( cap_from_text("all-eip") ); + + #elif !defined(HAVE_DOSISH_SYSTEM) + uid_t uid; + + disable_secmem=1; + uid = getuid(); + if( uid != geteuid() ) { + if( setuid( uid ) || getuid() != geteuid() ) + log_fatal("failed to drop setuid\n" ); + } + #endif + } + else { + if( n < DEFAULT_POOLSIZE ) + n = DEFAULT_POOLSIZE; + if( !pool_okay ) + init_pool(n); + else + log_error("Oops, secure memory pool already initialized\n"); + } +} + + +void * +secmem_malloc( size_t size ) +{ + MEMBLOCK *mb, *mb2; + int compressed=0; + + if( !pool_okay ) { + log_info( + _("operation is not possible without initialized secure memory\n")); + log_info(_("(you may have used the wrong program for this task)\n")); + exit(2); + } + if( show_warning && !suspend_warning ) { + show_warning = 0; + print_warn(); + } + + /* blocks are always a multiple of 32 */ + size += sizeof(MEMBLOCK); + size = ((size + 31) / 32) * 32; + + retry: + /* try to get it from the used blocks */ + for(mb = unused_blocks,mb2=NULL; mb; mb2=mb, mb = mb->u.next ) + if( mb->size >= size ) { + if( mb2 ) + mb2->u.next = mb->u.next; + else + unused_blocks = mb->u.next; + goto leave; + } + /* allocate a new block */ + if( (poollen + size <= poolsize) ) { + mb = (void*)((char*)pool + poollen); + poollen += size; + mb->size = size; + } + else if( !compressed ) { + compressed=1; + compress_pool(); + goto retry; + } + else + return NULL; + + leave: + cur_alloced += mb->size; + cur_blocks++; + if( cur_alloced > max_alloced ) + max_alloced = cur_alloced; + if( cur_blocks > max_blocks ) + max_blocks = cur_blocks; + + return &mb->u.aligned.c; +} + + +void * +secmem_realloc( void *p, size_t newsize ) +{ + MEMBLOCK *mb; + size_t size; + void *a; + + mb = (MEMBLOCK*)((char*)p - ((size_t) &((MEMBLOCK*)0)->u.aligned.c)); + size = mb->size; + if( newsize < size ) + return p; /* it is easier not to shrink the memory */ + a = secmem_malloc( newsize ); + memcpy(a, p, size); + memset((char*)a+size, 0, newsize-size); + secmem_free(p); + return a; +} + + +void +secmem_free( void *a ) +{ + MEMBLOCK *mb; + size_t size; + + if( !a ) + return; + + mb = (MEMBLOCK*)((char*)a - ((size_t) &((MEMBLOCK*)0)->u.aligned.c)); + size = mb->size; + /* This does not make much sense: probably this memory is held in the + * cache. We do it anyway: */ + memset(mb, 0xff, size ); + memset(mb, 0xaa, size ); + memset(mb, 0x55, size ); + memset(mb, 0x00, size ); + mb->size = size; + mb->u.next = unused_blocks; + unused_blocks = mb; + cur_blocks--; + cur_alloced -= size; +} + + +int +g10_private_is_secure( const void *p ) +{ + return p >= pool && p < (void*)((char*)pool+poolsize); +} + + + +/**************** + * Warning: This code might be called by an interrupt handler + * and frankly, there should really be such a handler, + * to make sure that the memory is wiped out. + * We hope that the OS wipes out mlocked memory after + * receiving a SIGKILL - it really should do so, otherwise + * there is no chance to get the secure memory cleaned. + */ +void +secmem_term() +{ + if( !pool_okay ) + return; + + memset( pool, 0xff, poolsize); + memset( pool, 0xaa, poolsize); + memset( pool, 0x55, poolsize); + memset( pool, 0x00, poolsize); + #if HAVE_MMAP + if( pool_is_mmapped ) + munmap( pool, poolsize ); + #endif + pool = NULL; + pool_okay = 0; + poolsize=0; + poollen=0; + unused_blocks=NULL; +} + + +void +secmem_dump_stats() +{ + if( disable_secmem ) + return; + fprintf(stderr, + "secmem usage: %u/%u bytes in %u/%u blocks of pool %lu/%lu\n", + cur_alloced, max_alloced, cur_blocks, max_blocks, + (ulong)poollen, (ulong)poolsize ); +} + diff --git a/src/secmem.h b/src/secmem.h new file mode 100644 index 00000000..e1feedf0 --- /dev/null +++ b/src/secmem.h @@ -0,0 +1,35 @@ +/* secmem.h - internal definitions for secmem + * Copyright (C) 2000 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG 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. + * + * GnuPG 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#ifndef G10_SECMEM_H +#define G10_SECMEM_H 1 + +void secmem_init( size_t npool ); +void secmem_term( void ); +void *secmem_malloc( size_t size ); +void *secmem_realloc( void *a, size_t newsize ); +void secmem_free( void *a ); +void secmem_dump_stats(void); +void secmem_set_flags( unsigned flags ); +unsigned secmem_get_flags(void); + +int g10_private_is_secure( const void *p ); + +#endif /* G10_SECMEM_H */ @@ -40,15 +40,6 @@ #include "memory.h" -/* FIXME: We should really have the m_lib functions to allow - * overriding of the default malloc functions - * For now use this kludge: */ -#define m_lib_alloc m_alloc -#define m_lib_alloc_clear m_alloc_clear -#define m_lib_free m_free - - - #if 0 struct sexp_node; @@ -173,11 +164,11 @@ gcry_sexp_new_data( const char *buffer, size_t length ) if( !length ) length = strlen(buffer); - node = m_alloc_clear( sizeof *node + length ); + node = g10_xcalloc( 1, sizeof *node + length ); node->type = ntDATA; node->u.data.len = length; memcpy(node->u.data.d, buffer, length ); - list = m_alloc_clear( sizeof *list ); + list = g10_xcalloc( 1, sizeof *list ); list->type = ntLIST; list->u.list = node; return list; @@ -191,10 +182,10 @@ gcry_sexp_new_mpi( GCRY_MPI mpi ) { NODE list, node; - node = m_alloc_clear( sizeof *node ); + node = g10_xcalloc( 1, sizeof *node ); node->type = ntMPI; node->u.mpi = gcry_mpi_copy( mpi ); - list = m_alloc_clear( sizeof *list ); + list = g10_xcalloc( 1, sizeof *list ); list->type = ntLIST; list->u.list = node; return list; @@ -254,7 +245,7 @@ gcry_sexp_cons( GCRY_SEXP a, GCRY_SEXP b ) } - head = m_alloc_clear( sizeof *head ); + head = g10_xcalloc( 1, sizeof *head ); head->type = ntLIST; if( !a->u.list->next ) { /* a has only one item */ NODE tmp = a; @@ -290,7 +281,7 @@ gcry_sexp_vlist( GCRY_SEXP a, ... ) fputs("sexp_vlist: arg 1 is not a list\n", stderr ); return NULL; } - head = m_alloc_clear( sizeof *node ); + head = g10_xcalloc( 1, sizeof *node ); head->type = ntLIST; if( !a->u.list->next ) { /* a has only one item */ NODE tmp = a; @@ -645,7 +636,7 @@ gcry_sexp_sscan( GCRY_SEXP *retsexp, const char *buffer, return -2; /* buffer too short */ } /* make a new list entry */ - node = m_alloc_clear( sizeof *node + datalen ); + node = g10_xcalloc( 1, sizeof *node + datalen ); if( first ) { /* stuff it into the first node */ first = 0; node->up = tail; @@ -687,7 +678,7 @@ gcry_sexp_sscan( GCRY_SEXP *retsexp, const char *buffer, *erroff = p - buffer; return -9; /* open display hint */ } - node = m_alloc_clear( sizeof *node ); + node = g10_xcalloc( 1, sizeof *node ); if( !head ) head = node; else { @@ -842,30 +833,30 @@ sexp_to_pk( GCRY_SEXP sexp, int want_private, MPI **retarray, int *retalgo) algo = algos[i].algo; elems1 = algos[i].common_elements; elems2 = want_private? algos[i].secret_elements : algos[i].public_elements; - array = m_lib_alloc_clear( (strlen(elems1)+strlen(elems2)+1) * sizeof *array ); + array = g10_xcalloc( (strlen(elems1)+strlen(elems2)+1) , sizeof *array ); idx = 0; for(s=elems1; *s; s++, idx++ ) { l2 = gcry_sexp_find_token( list, s, 1 ); if( !l2 ) { - m_lib_free( array ); + g10_free( array ); return -5; /* required parameter not found */ } array[idx] = gcry_sexp_cdr_mpi( l2, GCRYMPI_FMT_USG ); if( !array[idx] ) { - m_lib_free( array ); + g10_free( array ); return -6; /* required parameter is invalid */ } } for(s=elems2; *s; s++, idx++ ) { l2 = gcry_sexp_find_token( list, s, 1 ); if( !l2 ) { - m_lib_free( array ); + g10_free( array ); return -5; /* required parameter not found */ } /* FIXME: put the MPI in secure memory when needed */ array[idx] = gcry_sexp_cdr_mpi( l2, GCRYMPI_FMT_USG ); if( !array[idx] ) { - m_lib_free( array ); + g10_free( array ); return -6; /* required parameter is invalid */ } } diff --git a/src/stdmem.c b/src/stdmem.c new file mode 100644 index 00000000..073c385b --- /dev/null +++ b/src/stdmem.c @@ -0,0 +1,186 @@ +/* stdmem.c - private memory allocator + * Copyright (C) 1998, 2000 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG 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. + * + * GnuPG 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#include <config.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> + +#include "g10lib.h" +#include "stdmem.h" +#include "secmem.h" + + +#define MAGIC_NOR_BYTE 0x55 +#define MAGIC_SEC_BYTE 0xcc +#define MAGIC_END_BYTE 0xaa + +#if SIZEOF_UNSIGNED_LONG == 8 + #define EXTRA_ALIGN 4 +#else + #define EXTRA_ALIGN 0 +#endif + + +static int use_m_guard = 1; + +/**************** + * Warning: Never use this function after any of the functions + * here have been used. + */ +void +g10_private_enable_m_guard(void) +{ + use_m_guard = 1; +} + +/**************** + * Allocate memory of size n. + * Return NULL if we are out of memory. + */ +void * +g10_private_malloc( size_t n) +{ + if( use_m_guard ) { + char *p; + + if( !(p = malloc( n + EXTRA_ALIGN+5 )) ) + return NULL; + ((byte*)p)[EXTRA_ALIGN+0] = n; + ((byte*)p)[EXTRA_ALIGN+1] = n >> 8 ; + ((byte*)p)[EXTRA_ALIGN+2] = n >> 16 ; + ((byte*)p)[EXTRA_ALIGN+3] = MAGIC_NOR_BYTE; + p[4+EXTRA_ALIGN+n] = MAGIC_END_BYTE; + return p+EXTRA_ALIGN+4; + } + else { + return malloc( n ); + } +} + +/**************** + * Allocate memory of size n from the secure memory pool. + * Return NULL if we are out of memory. + */ +void * +g10_private_malloc_secure( size_t n) +{ + if( use_m_guard ) { + char *p; + + if( !(p = secmem_malloc( n +EXTRA_ALIGN+ 5 )) ) + return NULL; + ((byte*)p)[EXTRA_ALIGN+0] = n; + ((byte*)p)[EXTRA_ALIGN+1] = n >> 8 ; + ((byte*)p)[EXTRA_ALIGN+2] = n >> 16 ; + ((byte*)p)[EXTRA_ALIGN+3] = MAGIC_SEC_BYTE; + p[4+EXTRA_ALIGN+n] = MAGIC_END_BYTE; + return p+EXTRA_ALIGN+4; + } + else { + return secmem_malloc( n ); + } +} + + +/**************** + * realloc and clear the old space + * Return NULL if there is not enoug memory. + */ +void * +g10_private_realloc( void *a, size_t n ) +{ + if( use_m_guard ) { + unsigned char *p = a; + void *b; + size_t len; + + g10_private_check_heap(p); + len = p[-4]; + len |= p[-3] << 8; + len |= p[-2] << 16; + if( len >= n ) /* we don't shrink for now */ + return a; + if( p[-1] == MAGIC_SEC_BYTE ) + b = g10_private_malloc_secure(n); + else + b = g10_private_malloc(n); + if( !b ) + return NULL; + memcpy(b, a, len ); + memset(b+len, 0, n-len ); + g10_private_free( p ); + return b; + } + else if( g10_private_is_secure(a) ) { + return secmem_realloc( a, n ); + } + else { + return realloc( a, n ); + } +} + + +void +g10_private_check_heap( const void *a ) +{ + if( use_m_guard ) { + const byte *p = a; + size_t len; + + if( !p ) + return; + + if( !(p[-1] == MAGIC_NOR_BYTE || p[-1] == MAGIC_SEC_BYTE) ) + g10_log_fatal("memory at %p corrupted (underflow=%02x)\n", p, p[-1] ); + len = p[-4]; + len |= p[-3] << 8; + len |= p[-2] << 16; + if( p[len] != MAGIC_END_BYTE ) + g10_log_fatal("memory at %p corrupted (overflow=%02x)\n", p, p[-1] ); + } +} + +/**************** + * Free a memory block allocated by this opr the secmem module + */ +void +g10_private_free( void *a ) +{ + byte *p = a; + + if( !p ) + return; + if( use_m_guard ) { + g10_private_check_heap(p); + if( g10_private_is_secure(a) ) + secmem_free(p-EXTRA_ALIGN-4); + else { + free(p-EXTRA_ALIGN-4); + } + } + else if( g10_private_is_secure(a) ) + secmem_free(p); + else + free(p); +} + + diff --git a/src/stdmem.h b/src/stdmem.h new file mode 100644 index 00000000..f7e340fa --- /dev/null +++ b/src/stdmem.h @@ -0,0 +1,32 @@ +/* stdmem.h - internal definitions for stdmem + * Copyright (C) 2000 Free Software Foundation, Inc. + * + * This file is part of GnuPG. + * + * GnuPG 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. + * + * GnuPG 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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA + */ + +#ifndef G10_STDMEM_H +#define G10_STDMEM_H 1 + +void g10_private_enable_m_guard(void); + +void *g10_private_malloc( size_t n); +void *g10_private_malloc_secure( size_t n); +void *g10_private_realloc( void *a, size_t n ); +void g10_private_check_heap( const void *a ); +void g10_private_free( void *a ); + +#endif /* G10_STDMEM_H */ diff --git a/src/wrapper.c b/src/wrapper.c index 3b486de6..c38e0a4f 100644 --- a/src/wrapper.c +++ b/src/wrapper.c @@ -1,4 +1,4 @@ -/* wrapper.c - wrapper around some inertal functions +/* wrapper.c - wrapper around the internal functions * Copyright (C) 1999 Free Software Foundation, Inc. * * This file is part of GnuPG. @@ -38,4 +38,5 @@ void *gcry_xcalloc_secure( size_t n, size_t m ) void *gcry_xrealloc( void *a, size_t n ) { return g10_xrealloc( a, n ); } char *gcry_xstrdup( const char * a) { return g10_xstrdup( a); } void gcry_free( void *p ) { g10_free( p ); } +int gcry_is_secure( const void *p ) { g10_is_secure( p ); } |