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