util/
[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     long int pgsize_val;
223     size_t pgsize;
224
225     poolsize = n;
226
227     if( disable_secmem )
228         log_bug("secure memory is disabled");
229
230 #if defined(HAVE_SYSCONF) && defined(_SC_PAGESIZE)
231     pgsize_val = sysconf (_SC_PAGESIZE);
232 #elif defined(HAVE_GETPAGESIZE)
233     pgsize_val = getpagesize ();
234 #else
235     pgsize_val = -1;
236 #endif
237     pgsize = (pgsize_val != -1 && pgsize_val > 0)? pgsize_val : 4096;
238
239
240 #ifdef HAVE_MMAP
241     poolsize = (poolsize + pgsize -1 ) & ~(pgsize-1);
242 #ifdef MAP_ANONYMOUS
243        pool = mmap( 0, poolsize, PROT_READ|PROT_WRITE,
244                                  MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
245 #else /* map /dev/zero instead */
246     {   int fd;
247
248         fd = open("/dev/zero", O_RDWR);
249         if( fd == -1 ) {
250             log_error("can't open /dev/zero: %s\n", strerror(errno) );
251             pool = (void*)-1;
252         }
253         else {
254             pool = mmap( 0, poolsize, PROT_READ|PROT_WRITE,
255                                       MAP_PRIVATE, fd, 0);
256             close (fd);
257         }
258     }
259 #endif
260     if( pool == (void*)-1 )
261         log_info("can't mmap pool of %u bytes: %s - using malloc\n",
262                             (unsigned)poolsize, strerror(errno));
263     else {
264         pool_is_mmapped = 1;
265         pool_okay = 1;
266     }
267
268 #endif
269     if( !pool_okay ) {
270         pool = malloc( poolsize );
271         if( !pool )
272             log_fatal("can't allocate memory pool of %u bytes\n",
273                                                        (unsigned)poolsize);
274         else
275             pool_okay = 1;
276     }
277     lock_pool( pool, poolsize );
278     poollen = 0;
279 }
280
281
282 /* concatenate unused blocks */
283 static void
284 compress_pool(void)
285 {
286     /* fixme: we really should do this */
287 }
288
289 void
290 secmem_set_flags( unsigned flags )
291 {
292     int was_susp = suspend_warning;
293
294     no_warning = flags & 1;
295     suspend_warning = flags & 2;
296
297     /* and now issue the warning if it is not longer suspended */
298     if( was_susp && !suspend_warning && show_warning ) {
299         show_warning = 0;
300         print_warn();
301     }
302 }
303
304 unsigned
305 secmem_get_flags(void)
306 {
307     unsigned flags;
308
309     flags  = no_warning      ? 1:0;
310     flags |= suspend_warning ? 2:0;
311     return flags;
312 }
313
314 /* Returns 1 if memory was locked, 0 if not. */
315 int
316 secmem_init( size_t n )
317 {
318     if( !n ) {
319 #ifndef __riscos__
320 #ifdef USE_CAPABILITIES
321         /* drop all capabilities */
322         cap_set_proc( cap_from_text("all-eip") );
323
324 #elif !defined(HAVE_DOSISH_SYSTEM)
325         uid_t uid;
326
327         disable_secmem=1;
328         uid = getuid();
329         if( uid != geteuid() ) {
330             if( setuid( uid ) || getuid() != geteuid() || !setuid(0) )
331                 log_fatal("failed to drop setuid\n" );
332         }
333 #endif
334 #endif /* !__riscos__ */
335     }
336     else {
337         if( n < DEFAULT_POOLSIZE )
338             n = DEFAULT_POOLSIZE;
339         if( !pool_okay )
340             init_pool(n);
341         else
342             log_error("Oops, secure memory pool already initialized\n");
343     }
344
345     return !show_warning;
346 }
347
348
349 void *
350 secmem_malloc( size_t size )
351 {
352     MEMBLOCK *mb, *mb2;
353     int compressed=0;
354
355     if( !pool_okay ) {
356         log_info(
357          _("operation is not possible without initialized secure memory\n"));
358         log_info(_("(you may have used the wrong program for this task)\n"));
359         exit(2);
360     }
361     if( show_warning && !suspend_warning ) {
362         show_warning = 0;
363         print_warn();
364     }
365
366     /* Blocks are always a multiple of 32.  Note that we allocate an
367        extra of the size of an entire MEMBLOCK.  This is required
368        becuase we do not only need the SIZE info but also extra space
369        to chain up unused memory blocks.  */
370     size += sizeof(MEMBLOCK);
371     size = ((size + 31) / 32) * 32;
372
373   retry:
374     /* try to get it from the used blocks */
375     for(mb = unused_blocks,mb2=NULL; mb; mb2=mb, mb = mb->u.next )
376         if( mb->size >= size ) {
377             if( mb2 )
378                 mb2->u.next = mb->u.next;
379             else
380                 unused_blocks = mb->u.next;
381             goto leave;
382         }
383     /* allocate a new block */
384     if( (poollen + size <= poolsize) ) {
385         mb = (void*)((char*)pool + poollen);
386         poollen += size;
387         mb->size = size;
388     }
389     else if( !compressed ) {
390         compressed=1;
391         compress_pool();
392         goto retry;
393     }
394     else
395         return NULL;
396
397   leave:
398     cur_alloced += mb->size;
399     cur_blocks++;
400     if( cur_alloced > max_alloced )
401         max_alloced = cur_alloced;
402     if( cur_blocks > max_blocks )
403         max_blocks = cur_blocks;
404
405     return &mb->u.aligned.c;
406 }
407
408
409 void *
410 secmexrealloc( void *p, size_t newsize )
411 {
412     MEMBLOCK *mb;
413     size_t size;
414     void *a;
415
416     mb = (MEMBLOCK*)((char*)p - ((size_t) &((MEMBLOCK*)0)->u.aligned.c));
417     size = mb->size;
418     if (size < sizeof(MEMBLOCK))
419       log_bug ("secure memory corrupted at block %p\n", (void *)mb);
420     size -= ((size_t) &((MEMBLOCK*)0)->u.aligned.c);
421
422     if( newsize <= size )
423         return p; /* It is easier not to shrink the memory.  */
424     a = secmem_malloc( newsize );
425     if ( a ) {
426         memcpy(a, p, size);
427         memset((char*)a+size, 0, newsize-size);
428         secmem_free(p);
429     }
430     return a;
431 }
432
433
434 void
435 secmem_free( void *a )
436 {
437     MEMBLOCK *mb;
438     size_t size;
439
440     if( !a )
441         return;
442
443     mb = (MEMBLOCK*)((char*)a - ((size_t) &((MEMBLOCK*)0)->u.aligned.c));
444     size = mb->size;
445     /* This does not make much sense: probably this memory is held in the
446      * cache. We do it anyway: */
447     wipememory2(mb, 0xff, size );
448     wipememory2(mb, 0xaa, size );
449     wipememory2(mb, 0x55, size );
450     wipememory2(mb, 0x00, size );
451     mb->size = size;
452     mb->u.next = unused_blocks;
453     unused_blocks = mb;
454     cur_blocks--;
455     cur_alloced -= size;
456 }
457
458
459 /* Check whether P points into the pool.  */
460 static int
461 ptr_into_pool_p (const void *p)
462 {
463   /* We need to convert pointers to addresses.  This is required by
464      C-99 6.5.8 to avoid undefined behaviour.  Using size_t is at
465      least only implementation defined.  See also
466      http://lists.gnupg.org/pipermail/gcrypt-devel/2007-February/001102.html
467   */
468   size_t p_addr = (size_t)p;
469   size_t pool_addr = (size_t)pool;
470
471   return p_addr >= pool_addr && p_addr <  pool_addr+poolsize;
472 }
473
474
475 int
476 m_is_secure( const void *p )
477 {
478   return pool_okay && ptr_into_pool_p (p);
479 }
480
481
482
483 /****************
484  * Warning:  This code might be called by an interrupt handler
485  *           and frankly, there should really be such a handler,
486  *           to make sure that the memory is wiped out.
487  *           We hope that the OS wipes out mlocked memory after
488  *           receiving a SIGKILL - it really should do so, otherwise
489  *           there is no chance to get the secure memory cleaned.
490  */
491 void
492 secmem_term()
493 {
494     if( !pool_okay )
495         return;
496
497     wipememory2( pool, 0xff, poolsize);
498     wipememory2( pool, 0xaa, poolsize);
499     wipememory2( pool, 0x55, poolsize);
500     wipememory2( pool, 0x00, poolsize);
501 #ifdef HAVE_MMAP
502     if( pool_is_mmapped )
503         munmap( pool, poolsize );
504 #endif
505     pool = NULL;
506     pool_okay = 0;
507     poolsize=0;
508     poollen=0;
509     unused_blocks=NULL;
510 }
511
512
513 void
514 secmem_dump_stats()
515 {
516     if( disable_secmem )
517         return;
518     fprintf(stderr,
519                 "secmem usage: %u/%u bytes in %u/%u blocks of pool %lu/%lu\n",
520                 cur_alloced, max_alloced, cur_blocks, max_blocks,
521                 (ulong)poollen, (ulong)poolsize );
522 }