-
+ A0B28117315BD9560BE404C97E44252316FD19FF9CBC762BF5D46235034846155D5058E22A73D7010F78CF7442BA6624E2417A719FFCBE2F8A163090706E069C
mpi/secmem.c
(0 . 0)(1 . 519)
10690 /* secmem.c - memory allocation from a secure heap
10691 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
10692 * 2007 Free Software Foundation, Inc.
10693 *
10694 * This file is part of GnuPG.
10695 *
10696 * GnuPG is free software; you can redistribute it and/or modify
10697 * it under the terms of the GNU General Public License as published by
10698 * the Free Software Foundation; either version 3 of the License, or
10699 * (at your option) any later version.
10700 *
10701 * GnuPG is distributed in the hope that it will be useful,
10702 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10703 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10704 * GNU General Public License for more details.
10705 *
10706 * You should have received a copy of the GNU General Public License
10707 * along with this program; if not, see <http://www.gnu.org/licenses/>.
10708 */
10709
10710 #include <config.h>
10711 #include <stdio.h>
10712 #include <stdlib.h>
10713 #include <string.h>
10714 #include <errno.h>
10715 #include <stdarg.h>
10716 #include <unistd.h>
10717 #if defined(HAVE_MLOCK) || defined(HAVE_MMAP)
10718 #include <sys/mman.h>
10719 #include <sys/types.h>
10720 #include <fcntl.h>
10721 #ifdef USE_CAPABILITIES
10722 #include <sys/capability.h>
10723 #endif
10724 #ifdef HAVE_PLOCK
10725 #include <sys/lock.h>
10726 #endif
10727 #endif
10728
10729 #include "types.h"
10730 #include "memory.h"
10731 #include "util.h"
10732
10733 /* MinGW doesn't seem to prototype getpagesize, though it does have
10734 it. */
10735 #if !HAVE_DECL_GETPAGESIZE
10736 int getpagesize(void);
10737 #endif
10738
10739 #if defined(MAP_ANON) && !defined(MAP_ANONYMOUS)
10740 #define MAP_ANONYMOUS MAP_ANON
10741 #endif
10742 /* It seems that Slackware 7.1 does not know about EPERM */
10743 #if !defined(EPERM) && defined(ENOMEM)
10744 #define EPERM ENOMEM
10745 #endif
10746
10747
10748 #define DEFAULT_POOLSIZE 16384
10749
10750 typedef struct memblock_struct MEMBLOCK;
10751 struct memblock_struct {
10752 unsigned size;
10753 union {
10754 MEMBLOCK *next;
10755 PROPERLY_ALIGNED_TYPE aligned;
10756 } u;
10757 };
10758
10759
10760
10761 static void *pool;
10762 static volatile int pool_okay; /* may be checked in an atexit function */
10763 #ifdef HAVE_MMAP
10764 static volatile int pool_is_mmapped;
10765 #endif
10766 static size_t poolsize; /* allocated length */
10767 static size_t poollen; /* used length */
10768 static MEMBLOCK *unused_blocks;
10769 static unsigned max_alloced;
10770 static unsigned cur_alloced;
10771 static unsigned max_blocks;
10772 static unsigned cur_blocks;
10773 static int disable_secmem;
10774 static int show_warning;
10775 static int no_warning;
10776 static int suspend_warning;
10777
10778
10779 static void
10780 print_warn(void)
10781 {
10782 if (!no_warning)
10783 {
10784 log_info(_("WARNING: using insecure memory!\n"));
10785 log_info(_("please see http://www.gnupg.org/faq.html"
10786 " for more information\n"));
10787 }
10788 }
10789
10790
10791 static void
10792 lock_pool( void *p, size_t n )
10793 {
10794 #if defined(USE_CAPABILITIES) && defined(HAVE_MLOCK)
10795 int err;
10796
10797 cap_set_proc( cap_from_text("cap_ipc_lock+ep") );
10798 err = mlock( p, n );
10799 if( err && errno )
10800 err = errno;
10801 cap_set_proc( cap_from_text("cap_ipc_lock+p") );
10802
10803 if( err ) {
10804 if( errno != EPERM
10805 #ifdef EAGAIN /* OpenBSD returns this */
10806 && errno != EAGAIN
10807 #endif
10808 #ifdef ENOSYS /* Some SCOs return this (function not implemented) */
10809 && errno != ENOSYS
10810 #endif
10811 #ifdef ENOMEM /* Linux can return this */
10812 && errno != ENOMEM
10813 #endif
10814 )
10815 log_error("can't lock memory: %s\n", strerror(err));
10816 show_warning = 1;
10817 }
10818
10819 #elif defined(HAVE_MLOCK)
10820 uid_t uid;
10821 int err;
10822
10823 uid = getuid();
10824
10825 #ifdef HAVE_BROKEN_MLOCK
10826 /* ick. but at least we get secured memory. about to lock
10827 entire data segment. */
10828 #ifdef HAVE_PLOCK
10829 # ifdef _AIX
10830 /* The configure for AIX returns broken mlock but the plock has
10831 the strange requirement to somehow set the stack limit first.
10832 The problem might turn out in indeterministic program behaviour
10833 and hanging processes which can somehow be solved when enough
10834 processes are clogging up the memory. To get this problem out
10835 of the way we simply don't try to lock the memory at all.
10836 */
10837 errno = EPERM;
10838 err = errno;
10839 # else /* !_AIX */
10840 err = plock( DATLOCK );
10841 if( err && errno )
10842 err = errno;
10843 # endif /*_AIX*/
10844 #else /*!HAVE_PLOCK*/
10845 if( uid ) {
10846 errno = EPERM;
10847 err = errno;
10848 }
10849 else {
10850 err = mlock( p, n );
10851 if( err && errno )
10852 err = errno;
10853 }
10854 #endif /*!HAVE_PLOCK*/
10855 #else
10856 err = mlock( p, n );
10857 if( err && errno )
10858 err = errno;
10859 #endif
10860
10861 if( uid && !geteuid() ) {
10862 /* check that we really dropped the privs.
10863 * Note: setuid(0) should always fail */
10864 if( setuid( uid ) || getuid() != geteuid() || !setuid(0) )
10865 log_fatal("failed to reset uid: %s\n", strerror(errno));
10866 }
10867
10868 if( err ) {
10869 if( errno != EPERM
10870 #ifdef EAGAIN /* OpenBSD returns this */
10871 && errno != EAGAIN
10872 #endif
10873 #ifdef ENOSYS /* Some SCOs return this (function not implemented) */
10874 && errno != ENOSYS
10875 #endif
10876 #ifdef ENOMEM /* Linux can return this */
10877 && errno != ENOMEM
10878 #endif
10879 )
10880 log_error("can't lock memory: %s\n", strerror(err));
10881 show_warning = 1;
10882 }
10883
10884 #elif defined ( __QNX__ )
10885 /* QNX does not page at all, so the whole secure memory stuff does
10886 * not make much sense. However it is still of use because it
10887 * wipes out the memory on a free().
10888 * Therefore it is sufficient to suppress the warning
10889 */
10890 #elif defined (HAVE_DOSISH_SYSTEM) || defined (__CYGWIN__)
10891 /* It does not make sense to print such a warning, given the fact that
10892 * this whole Windows !@#$% and their user base are inherently insecure
10893 */
10894 #elif defined (__riscos__)
10895 /* no virtual memory on RISC OS, so no pages are swapped to disc,
10896 * besides we don't have mmap, so we don't use it! ;-)
10897 * But don't complain, as explained above.
10898 */
10899 #else
10900 log_info("Please note that you don't have secure memory on this system\n");
10901 #endif
10902 }
10903
10904
10905 static void
10906 init_pool( size_t n)
10907 {
10908 long int pgsize_val;
10909 size_t pgsize;
10910
10911 poolsize = n;
10912
10913 if( disable_secmem )
10914 log_bug("secure memory is disabled");
10915
10916 #if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
10917 pgsize_val = sysconf (_SC_PAGESIZE);
10918 #elif defined(HAVE_GETPAGESIZE)
10919 pgsize_val = getpagesize ();
10920 #else
10921 pgsize_val = -1;
10922 #endif
10923 pgsize = (pgsize_val != -1 && pgsize_val > 0)? pgsize_val : 4096;
10924
10925
10926 #ifdef HAVE_MMAP
10927 poolsize = (poolsize + pgsize -1 ) & ~(pgsize-1);
10928 #ifdef MAP_ANONYMOUS
10929 pool = mmap( 0, poolsize, PROT_READ|PROT_WRITE,
10930 MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
10931 #else /* map /dev/zero instead */
10932 { int fd;
10933
10934 fd = open("/dev/zero", O_RDWR);
10935 if( fd == -1 ) {
10936 log_error("can't open /dev/zero: %s\n", strerror(errno) );
10937 pool = (void*)-1;
10938 }
10939 else {
10940 pool = mmap( 0, poolsize, PROT_READ|PROT_WRITE,
10941 MAP_PRIVATE, fd, 0);
10942 close (fd);
10943 }
10944 }
10945 #endif
10946 if( pool == (void*)-1 )
10947 log_info("can't mmap pool of %u bytes: %s - using malloc\n",
10948 (unsigned)poolsize, strerror(errno));
10949 else {
10950 pool_is_mmapped = 1;
10951 pool_okay = 1;
10952 }
10953
10954 #endif
10955 if( !pool_okay ) {
10956 pool = malloc( poolsize );
10957 if( !pool )
10958 log_fatal("can't allocate memory pool of %u bytes\n",
10959 (unsigned)poolsize);
10960 else
10961 pool_okay = 1;
10962 }
10963 lock_pool( pool, poolsize );
10964 poollen = 0;
10965 }
10966
10967
10968 /* concatenate unused blocks */
10969 static void
10970 compress_pool(void)
10971 {
10972 /* fixme: we really should do this */
10973 }
10974
10975 void
10976 secmem_set_flags( unsigned flags )
10977 {
10978 int was_susp = suspend_warning;
10979
10980 no_warning = flags & 1;
10981 suspend_warning = flags & 2;
10982
10983 /* and now issue the warning if it is not longer suspended */
10984 if( was_susp && !suspend_warning && show_warning ) {
10985 show_warning = 0;
10986 print_warn();
10987 }
10988 }
10989
10990 unsigned
10991 secmem_get_flags(void)
10992 {
10993 unsigned flags;
10994
10995 flags = no_warning ? 1:0;
10996 flags |= suspend_warning ? 2:0;
10997 return flags;
10998 }
10999
11000 /* Returns 1 if memory was locked, 0 if not. */
11001 int
11002 secmem_init( size_t n )
11003 {
11004 if( !n ) {
11005 #ifndef __riscos__
11006 #ifdef USE_CAPABILITIES
11007 /* drop all capabilities */
11008 cap_set_proc( cap_from_text("all-eip") );
11009
11010 #elif !defined(HAVE_DOSISH_SYSTEM)
11011 uid_t uid;
11012
11013 disable_secmem=1;
11014 uid = getuid();
11015 if( uid != geteuid() ) {
11016 if( setuid( uid ) || getuid() != geteuid() || !setuid(0) )
11017 log_fatal("failed to drop setuid\n" );
11018 }
11019 #endif
11020 #endif /* !__riscos__ */
11021 }
11022 else {
11023 if( n < DEFAULT_POOLSIZE )
11024 n = DEFAULT_POOLSIZE;
11025 if( !pool_okay )
11026 init_pool(n);
11027 else
11028 log_error("Oops, secure memory pool already initialized\n");
11029 }
11030
11031 return !show_warning;
11032 }
11033
11034
11035 void *
11036 secmem_malloc( size_t size )
11037 {
11038 MEMBLOCK *mb, *mb2;
11039 int compressed=0;
11040
11041 if( !pool_okay ) {
11042 log_info(
11043 _("operation is not possible without initialized secure memory\n"));
11044 log_info(_("(you may have used the wrong program for this task)\n"));
11045 exit(2);
11046 }
11047 if( show_warning && !suspend_warning ) {
11048 show_warning = 0;
11049 print_warn();
11050 }
11051
11052 /* Blocks are always a multiple of 32. Note that we allocate an
11053 extra of the size of an entire MEMBLOCK. This is required
11054 becuase we do not only need the SIZE info but also extra space
11055 to chain up unused memory blocks. */
11056 size += sizeof(MEMBLOCK);
11057 size = ((size + 31) / 32) * 32;
11058
11059 retry:
11060 /* try to get it from the used blocks */
11061 for(mb = unused_blocks,mb2=NULL; mb; mb2=mb, mb = mb->u.next )
11062 if( mb->size >= size ) {
11063 if( mb2 )
11064 mb2->u.next = mb->u.next;
11065 else
11066 unused_blocks = mb->u.next;
11067 goto leave;
11068 }
11069 /* allocate a new block */
11070 if( (poollen + size <= poolsize) ) {
11071 mb = (void*)((char*)pool + poollen);
11072 poollen += size;
11073 mb->size = size;
11074 }
11075 else if( !compressed ) {
11076 compressed=1;
11077 compress_pool();
11078 goto retry;
11079 }
11080 else
11081 return NULL;
11082
11083 leave:
11084 cur_alloced += mb->size;
11085 cur_blocks++;
11086 if( cur_alloced > max_alloced )
11087 max_alloced = cur_alloced;
11088 if( cur_blocks > max_blocks )
11089 max_blocks = cur_blocks;
11090
11091 return &mb->u.aligned.c;
11092 }
11093
11094
11095 void *
11096 secmexrealloc( void *p, size_t newsize )
11097 {
11098 MEMBLOCK *mb;
11099 size_t size;
11100 void *a;
11101
11102 mb = (MEMBLOCK*)((char*)p - ((size_t) &((MEMBLOCK*)0)->u.aligned.c));
11103 size = mb->size;
11104 if (size < sizeof(MEMBLOCK))
11105 log_bug ("secure memory corrupted at block %p\n", (void *)mb);
11106 size -= ((size_t) &((MEMBLOCK*)0)->u.aligned.c);
11107
11108 if( newsize <= size )
11109 return p; /* It is easier not to shrink the memory. */
11110 a = secmem_malloc( newsize );
11111 if ( a ) {
11112 memcpy(a, p, size);
11113 memset((char*)a+size, 0, newsize-size);
11114 secmem_free(p);
11115 }
11116 return a;
11117 }
11118
11119
11120 void
11121 secmem_free( void *a )
11122 {
11123 MEMBLOCK *mb;
11124 size_t size;
11125
11126 if( !a )
11127 return;
11128
11129 mb = (MEMBLOCK*)((char*)a - ((size_t) &((MEMBLOCK*)0)->u.aligned.c));
11130 size = mb->size;
11131 /* This does not make much sense: probably this memory is held in the
11132 * cache. We do it anyway: */
11133 wipememory2(mb, 0xff, size );
11134 wipememory2(mb, 0xaa, size );
11135 wipememory2(mb, 0x55, size );
11136 wipememory2(mb, 0x00, size );
11137 mb->size = size;
11138 mb->u.next = unused_blocks;
11139 unused_blocks = mb;
11140 cur_blocks--;
11141 cur_alloced -= size;
11142 }
11143
11144
11145 /* Check whether P points into the pool. */
11146 static int
11147 ptr_into_pool_p (const void *p)
11148 {
11149 /* We need to convert pointers to addresses. This is required by
11150 C-99 6.5.8 to avoid undefined behaviour. Using size_t is at
11151 least only implementation defined. See also
11152 http://lists.gnupg.org/pipermail/gcrypt-devel/2007-February/001102.html
11153 */
11154 size_t p_addr = (size_t)p;
11155 size_t pool_addr = (size_t)pool;
11156
11157 return p_addr >= pool_addr && p_addr < pool_addr+poolsize;
11158 }
11159
11160
11161 int
11162 m_is_secure( const void *p )
11163 {
11164 return pool_okay && ptr_into_pool_p (p);
11165 }
11166
11167
11168
11169 /****************
11170 * Warning: This code might be called by an interrupt handler
11171 * and frankly, there should really be such a handler,
11172 * to make sure that the memory is wiped out.
11173 * We hope that the OS wipes out mlocked memory after
11174 * receiving a SIGKILL - it really should do so, otherwise
11175 * there is no chance to get the secure memory cleaned.
11176 */
11177 void
11178 secmem_term()
11179 {
11180 if( !pool_okay )
11181 return;
11182
11183 wipememory2( pool, 0xff, poolsize);
11184 wipememory2( pool, 0xaa, poolsize);
11185 wipememory2( pool, 0x55, poolsize);
11186 wipememory2( pool, 0x00, poolsize);
11187 #ifdef HAVE_MMAP
11188 if( pool_is_mmapped )
11189 munmap( pool, poolsize );
11190 #endif
11191 pool = NULL;
11192 pool_okay = 0;
11193 poolsize=0;
11194 poollen=0;
11195 unused_blocks=NULL;
11196 }
11197
11198
11199 void
11200 secmem_dump_stats()
11201 {
11202 if( disable_secmem )
11203 return;
11204 fprintf(stderr,
11205 "secmem usage: %u/%u bytes in %u/%u blocks of pool %lu/%lu\n",
11206 cur_alloced, max_alloced, cur_blocks, max_blocks,
11207 (ulong)poollen, (ulong)poolsize );
11208 }