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