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