Use sysconf() when possible as not all platforms have getpagesize().
[gnupg.git] / util / secmem.c
1 /* secmem.c  -  memory allocation from a secure heap
2  *      Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
3  *                    2007 Free Software Foundation, Inc.
4  *
5  * This file is part of GnuPG.
6  *
7  * GnuPG is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * GnuPG is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
20  * USA.
21  */
22
23 #include <config.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <errno.h>
28 #include <stdarg.h>
29 #include <unistd.h>
30 #if defined(HAVE_MLOCK) || defined(HAVE_MMAP)
31 #include <sys/mman.h>
32 #include <sys/types.h>
33 #include <fcntl.h>
34 #ifdef USE_CAPABILITIES
35 #include <sys/capability.h>
36 #endif
37 #ifdef HAVE_PLOCK
38 #include <sys/lock.h>
39 #endif
40 #endif
41
42 #include "types.h"
43 #include "memory.h"
44 #include "util.h"
45 #include "i18n.h"
46
47 /* MinGW doesn't seem to prototype getpagesize, though it does have
48    it. */
49 #if !HAVE_DECL_GETPAGESIZE
50 int getpagesize(void);
51 #endif
52
53 #if defined(MAP_ANON) && !defined(MAP_ANONYMOUS)
54 #define MAP_ANONYMOUS MAP_ANON
55 #endif
56 /* It seems that Slackware 7.1 does not know about EPERM */
57 #if !defined(EPERM) && defined(ENOMEM)
58 #define EPERM  ENOMEM
59 #endif
60
61
62 #define DEFAULT_POOLSIZE 16384
63
64 typedef struct memblock_struct MEMBLOCK;
65 struct memblock_struct {
66     unsigned size;
67     union {
68         MEMBLOCK *next;
69         PROPERLY_ALIGNED_TYPE aligned;
70     } u;
71 };
72
73
74
75 static void  *pool;
76 static volatile int pool_okay; /* may be checked in an atexit function */
77 #ifdef HAVE_MMAP
78 static volatile int pool_is_mmapped;
79 #endif
80 static size_t poolsize; /* allocated length */
81 static size_t poollen;  /* used length */
82 static MEMBLOCK *unused_blocks;
83 static unsigned max_alloced;
84 static unsigned cur_alloced;
85 static unsigned max_blocks;
86 static unsigned cur_blocks;
87 static int disable_secmem;
88 static int show_warning;
89 static int no_warning;
90 static int suspend_warning;
91
92
93 static void
94 print_warn(void)
95 {
96   if (!no_warning)
97     {
98       log_info(_("WARNING: using insecure memory!\n"));
99       log_info(_("please see http://www.gnupg.org/faq.html"
100                  " for more information\n"));
101     }
102 }
103
104
105 static void
106 lock_pool( void *p, size_t n )
107 {
108 #if defined(USE_CAPABILITIES) && defined(HAVE_MLOCK)
109     int err;
110
111     cap_set_proc( cap_from_text("cap_ipc_lock+ep") );
112     err = mlock( p, n );
113     if( err && errno )
114         err = errno;
115     cap_set_proc( cap_from_text("cap_ipc_lock+p") );
116
117     if( err ) {
118         if( errno != EPERM
119 #ifdef EAGAIN  /* OpenBSD returns this */
120             && errno != EAGAIN
121 #endif
122 #ifdef ENOSYS  /* Some SCOs return this (function not implemented) */
123             && errno != ENOSYS
124 #endif
125 #ifdef ENOMEM  /* Linux can return this */
126             && errno != ENOMEM
127 #endif
128           )
129             log_error("can't lock memory: %s\n", strerror(err));
130         show_warning = 1;
131     }
132
133 #elif defined(HAVE_MLOCK)
134     uid_t uid;
135     int err;
136
137     uid = getuid();
138
139 #ifdef HAVE_BROKEN_MLOCK
140     /* ick. but at least we get secured memory. about to lock
141        entire data segment. */
142 #ifdef HAVE_PLOCK
143 # ifdef _AIX
144     /* The configure for AIX returns broken mlock but the plock has
145        the strange requirement to somehow set the stack limit first.
146        The problem might turn out in indeterministic program behaviour
147        and hanging processes which can somehow be solved when enough
148        processes are clogging up the memory.  To get this problem out
149        of the way we simply don't try to lock the memory at all.
150        */    
151     errno = EPERM;
152     err = errno;
153 # else /* !_AIX */
154     err = plock( DATLOCK );
155     if( err && errno )
156         err = errno;
157 # endif /*_AIX*/
158 #else /*!HAVE_PLOCK*/
159     if( uid ) {
160         errno = EPERM;
161         err = errno;
162     }
163     else {
164         err = mlock( p, n );
165         if( err && errno )
166             err = errno;
167     }
168 #endif /*!HAVE_PLOCK*/
169 #else
170     err = mlock( p, n );
171     if( err && errno )
172         err = errno;
173 #endif
174
175     if( uid && !geteuid() ) {
176         /* check that we really dropped the privs.
177          * Note: setuid(0) should always fail */
178         if( setuid( uid ) || getuid() != geteuid() || !setuid(0) )
179             log_fatal("failed to reset uid: %s\n", strerror(errno));
180     }
181
182     if( err ) {
183         if( errno != EPERM
184 #ifdef EAGAIN  /* OpenBSD returns this */
185             && errno != EAGAIN
186 #endif
187 #ifdef ENOSYS  /* Some SCOs return this (function not implemented) */
188             && errno != ENOSYS
189 #endif
190 #ifdef ENOMEM  /* Linux can return this */
191             && errno != ENOMEM
192 #endif
193           )
194             log_error("can't lock memory: %s\n", strerror(err));
195         show_warning = 1;
196     }
197
198 #elif defined ( __QNX__ )
199     /* QNX does not page at all, so the whole secure memory stuff does
200      * not make much sense.  However it is still of use because it
201      * wipes out the memory on a free().
202      * Therefore it is sufficient to suppress the warning
203      */
204 #elif defined (HAVE_DOSISH_SYSTEM) || defined (__CYGWIN__)
205     /* It does not make sense to print such a warning, given the fact that 
206      * this whole Windows !@#$% and their user base are inherently insecure
207      */
208 #elif defined (__riscos__)
209     /* no virtual memory on RISC OS, so no pages are swapped to disc,
210      * besides we don't have mmap, so we don't use it! ;-)
211      * But don't complain, as explained above.
212      */
213 #else
214     log_info("Please note that you don't have secure memory on this system\n");
215 #endif
216 }
217
218
219 static void
220 init_pool( size_t n)
221 {
222     size_t pgsize=-1;
223
224     poolsize = n;
225
226     if( disable_secmem )
227         log_bug("secure memory is disabled");
228
229 #if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
230     pgsize = sysconf(_SC_PAGESIZE);
231 #elif defined(HAVE_GETPAGESIZE)
232     pgsize = getpagesize();
233 #endif
234
235     if(pgsize==-1)
236       pgsize = 4096;
237
238 #ifdef HAVE_MMAP
239     poolsize = (poolsize + pgsize -1 ) & ~(pgsize-1);
240 #ifdef MAP_ANONYMOUS
241        pool = mmap( 0, poolsize, PROT_READ|PROT_WRITE,
242                                  MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
243 #else /* map /dev/zero instead */
244     {   int fd;
245
246         fd = open("/dev/zero", O_RDWR);
247         if( fd == -1 ) {
248             log_error("can't open /dev/zero: %s\n", strerror(errno) );
249             pool = (void*)-1;
250         }
251         else {
252             pool = mmap( 0, poolsize, PROT_READ|PROT_WRITE,
253                                       MAP_PRIVATE, fd, 0);
254             close (fd);
255         }
256     }
257 #endif
258     if( pool == (void*)-1 )
259         log_info("can't mmap pool of %u bytes: %s - using malloc\n",
260                             (unsigned)poolsize, strerror(errno));
261     else {
262         pool_is_mmapped = 1;
263         pool_okay = 1;
264     }
265
266 #endif
267     if( !pool_okay ) {
268         pool = malloc( poolsize );
269         if( !pool )
270             log_fatal("can't allocate memory pool of %u bytes\n",
271                                                        (unsigned)poolsize);
272         else
273             pool_okay = 1;
274     }
275     lock_pool( pool, poolsize );
276     poollen = 0;
277 }
278
279
280 /* concatenate unused blocks */
281 static void
282 compress_pool(void)
283 {
284     /* fixme: we really should do this */
285 }
286
287 void
288 secmem_set_flags( unsigned flags )
289 {
290     int was_susp = suspend_warning;
291
292     no_warning = flags & 1;
293     suspend_warning = flags & 2;
294
295     /* and now issue the warning if it is not longer suspended */
296     if( was_susp && !suspend_warning && show_warning ) {
297         show_warning = 0;
298         print_warn();
299     }
300 }
301
302 unsigned
303 secmem_get_flags(void)
304 {
305     unsigned flags;
306
307     flags  = no_warning      ? 1:0;
308     flags |= suspend_warning ? 2:0;
309     return flags;
310 }
311
312 /* Returns 1 if memory was locked, 0 if not. */
313 int
314 secmem_init( size_t n )
315 {
316     if( !n ) {
317 #ifndef __riscos__
318 #ifdef USE_CAPABILITIES
319         /* drop all capabilities */
320         cap_set_proc( cap_from_text("all-eip") );
321
322 #elif !defined(HAVE_DOSISH_SYSTEM)
323         uid_t uid;
324
325         disable_secmem=1;
326         uid = getuid();
327         if( uid != geteuid() ) {
328             if( setuid( uid ) || getuid() != geteuid() || !setuid(0) )
329                 log_fatal("failed to drop setuid\n" );
330         }
331 #endif
332 #endif /* !__riscos__ */
333     }
334     else {
335         if( n < DEFAULT_POOLSIZE )
336             n = DEFAULT_POOLSIZE;
337         if( !pool_okay )
338             init_pool(n);
339         else
340             log_error("Oops, secure memory pool already initialized\n");
341     }
342
343     return !show_warning;
344 }
345
346
347 void *
348 secmem_malloc( size_t size )
349 {
350     MEMBLOCK *mb, *mb2;
351     int compressed=0;
352
353     if( !pool_okay ) {
354         log_info(
355          _("operation is not possible without initialized secure memory\n"));
356         log_info(_("(you may have used the wrong program for this task)\n"));
357         exit(2);
358     }
359     if( show_warning && !suspend_warning ) {
360         show_warning = 0;
361         print_warn();
362     }
363
364     /* Blocks are always a multiple of 32.  Note that we allocate an
365        extra of the size of an entire MEMBLOCK.  This is required
366        becuase we do not only need the SIZE info but also extra space
367        to chain up unused memory blocks.  */
368     size += sizeof(MEMBLOCK);
369     size = ((size + 31) / 32) * 32;
370
371   retry:
372     /* try to get it from the used blocks */
373     for(mb = unused_blocks,mb2=NULL; mb; mb2=mb, mb = mb->u.next )
374         if( mb->size >= size ) {
375             if( mb2 )
376                 mb2->u.next = mb->u.next;
377             else
378                 unused_blocks = mb->u.next;
379             goto leave;
380         }
381     /* allocate a new block */
382     if( (poollen + size <= poolsize) ) {
383         mb = (void*)((char*)pool + poollen);
384         poollen += size;
385         mb->size = size;
386     }
387     else if( !compressed ) {
388         compressed=1;
389         compress_pool();
390         goto retry;
391     }
392     else
393         return NULL;
394
395   leave:
396     cur_alloced += mb->size;
397     cur_blocks++;
398     if( cur_alloced > max_alloced )
399         max_alloced = cur_alloced;
400     if( cur_blocks > max_blocks )
401         max_blocks = cur_blocks;
402
403     return &mb->u.aligned.c;
404 }
405
406
407 void *
408 secmexrealloc( void *p, size_t newsize )
409 {
410     MEMBLOCK *mb;
411     size_t size;
412     void *a;
413
414     mb = (MEMBLOCK*)((char*)p - ((size_t) &((MEMBLOCK*)0)->u.aligned.c));
415     size = mb->size;
416     if (size < sizeof(MEMBLOCK))
417       log_bug ("secure memory corrupted at block %p\n", (void *)mb);
418     size -= ((size_t) &((MEMBLOCK*)0)->u.aligned.c);
419
420     if( newsize <= size )
421         return p; /* It is easier not to shrink the memory.  */
422     a = secmem_malloc( newsize );
423     if ( a ) {
424         memcpy(a, p, size);
425         memset((char*)a+size, 0, newsize-size);
426         secmem_free(p);
427     }
428     return a;
429 }
430
431
432 void
433 secmem_free( void *a )
434 {
435     MEMBLOCK *mb;
436     size_t size;
437
438     if( !a )
439         return;
440
441     mb = (MEMBLOCK*)((char*)a - ((size_t) &((MEMBLOCK*)0)->u.aligned.c));
442     size = mb->size;
443     /* This does not make much sense: probably this memory is held in the
444      * cache. We do it anyway: */
445     wipememory2(mb, 0xff, size );
446     wipememory2(mb, 0xaa, size );
447     wipememory2(mb, 0x55, size );
448     wipememory2(mb, 0x00, size );
449     mb->size = size;
450     mb->u.next = unused_blocks;
451     unused_blocks = mb;
452     cur_blocks--;
453     cur_alloced -= size;
454 }
455
456
457 /* Check whether P points into the pool.  */
458 static int
459 ptr_into_pool_p (const void *p)
460 {
461   /* We need to convert pointers to addresses.  This is required by
462      C-99 6.5.8 to avoid undefined behaviour.  Using size_t is at
463      least only implementation defined.  See also
464      http://lists.gnupg.org/pipermail/gcrypt-devel/2007-February/001102.html
465   */
466   size_t p_addr = (size_t)p;
467   size_t pool_addr = (size_t)pool;
468
469   return p_addr >= pool_addr && p_addr <  pool_addr+poolsize;
470 }
471
472
473 int
474 m_is_secure( const void *p )
475 {
476   return pool_okay && ptr_into_pool_p (p);
477 }
478
479
480
481 /****************
482  * Warning:  This code might be called by an interrupt handler
483  *           and frankly, there should really be such a handler,
484  *           to make sure that the memory is wiped out.
485  *           We hope that the OS wipes out mlocked memory after
486  *           receiving a SIGKILL - it really should do so, otherwise
487  *           there is no chance to get the secure memory cleaned.
488  */
489 void
490 secmem_term()
491 {
492     if( !pool_okay )
493         return;
494
495     wipememory2( pool, 0xff, poolsize);
496     wipememory2( pool, 0xaa, poolsize);
497     wipememory2( pool, 0x55, poolsize);
498     wipememory2( pool, 0x00, poolsize);
499 #ifdef HAVE_MMAP
500     if( pool_is_mmapped )
501         munmap( pool, poolsize );
502 #endif
503     pool = NULL;
504     pool_okay = 0;
505     poolsize=0;
506     poollen=0;
507     unused_blocks=NULL;
508 }
509
510
511 void
512 secmem_dump_stats()
513 {
514     if( disable_secmem )
515         return;
516     fprintf(stderr,
517                 "secmem usage: %u/%u bytes in %u/%u blocks of pool %lu/%lu\n",
518                 cur_alloced, max_alloced, cur_blocks, max_blocks,
519                 (ulong)poollen, (ulong)poolsize );
520 }