* secmem.c (lock_pool) [__CYGWIN__]: Don't print secmem warning. From
[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     err = plock( DATLOCK );
136     if( err && errno )
137         err = errno;
138 #else /*!HAVE_PLOCK*/
139     if( uid ) {
140         errno = EPERM;
141         err = errno;
142     }
143     else {
144         err = mlock( p, n );
145         if( err && errno )
146             err = errno;
147     }
148   #endif /*!HAVE_PLOCK*/
149   #else
150     err = mlock( p, n );
151     if( err && errno )
152         err = errno;
153   #endif
154
155     if( uid && !geteuid() ) {
156         /* check that we really dropped the privs.
157          * Note: setuid(0) should always fail */
158         if( setuid( uid ) || getuid() != geteuid() || !setuid(0) )
159             log_fatal("failed to reset uid: %s\n", strerror(errno));
160     }
161
162     if( err ) {
163         if( errno != EPERM
164           #ifdef EAGAIN  /* OpenBSD returns this */
165             && errno != EAGAIN
166           #endif
167           #ifdef ENOSYS  /* Some SCOs return this (function not implemented) */
168             && errno != ENOSYS
169           #endif
170           #ifdef ENOMEM  /* Linux can return this */
171             && errno != ENOMEM
172           #endif
173           )
174             log_error("can't lock memory: %s\n", strerror(err));
175         show_warning = 1;
176     }
177
178   #elif defined ( __QNX__ )
179     /* QNX does not page at all, so the whole secure memory stuff does
180      * not make much sense.  However it is still of use because it
181      * wipes out the memory on a free().
182      * Therefore it is sufficient to suppress the warning
183      */
184   #elif defined (HAVE_DOSISH_SYSTEM) || defined (__CYGWIN__)
185     /* It does not make sense to print such a warning, given the fact that 
186      * this whole Windows !@#$% and their user base are inherently insecure
187      */
188   #elif defined (__riscos__)
189     /* no virtual memory on RISC OS, so no pages are swapped to disc,
190      * besides we don't have mmap, so we don't use it! ;-)
191      * But don't complain, as explained above.
192      */
193   #else
194     log_info("Please note that you don't have secure memory on this system\n");
195   #endif
196 }
197
198
199 static void
200 init_pool( size_t n)
201 {
202     size_t pgsize;
203
204     poolsize = n;
205
206     if( disable_secmem )
207         log_bug("secure memory is disabled");
208
209   #ifdef HAVE_GETPAGESIZE
210     pgsize = getpagesize();
211   #else
212     pgsize = 4096;
213   #endif
214
215   #ifdef HAVE_MMAP
216     poolsize = (poolsize + pgsize -1 ) & ~(pgsize-1);
217     #ifdef MAP_ANONYMOUS
218        pool = mmap( 0, poolsize, PROT_READ|PROT_WRITE,
219                                  MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
220     #else /* map /dev/zero instead */
221     {   int fd;
222
223         fd = open("/dev/zero", O_RDWR);
224         if( fd == -1 ) {
225             log_error("can't open /dev/zero: %s\n", strerror(errno) );
226             pool = (void*)-1;
227         }
228         else {
229             pool = mmap( 0, poolsize, PROT_READ|PROT_WRITE,
230                                       MAP_PRIVATE, fd, 0);
231         }
232     }
233     #endif
234     if( pool == (void*)-1 )
235         log_info("can't mmap pool of %u bytes: %s - using malloc\n",
236                             (unsigned)poolsize, strerror(errno));
237     else {
238         pool_is_mmapped = 1;
239         pool_okay = 1;
240     }
241
242   #endif
243     if( !pool_okay ) {
244         pool = malloc( poolsize );
245         if( !pool )
246             log_fatal("can't allocate memory pool of %u bytes\n",
247                                                        (unsigned)poolsize);
248         else
249             pool_okay = 1;
250     }
251     lock_pool( pool, poolsize );
252     poollen = 0;
253 }
254
255
256 /* concatenate unused blocks */
257 static void
258 compress_pool(void)
259 {
260     /* fixme: we really should do this */
261 }
262
263 void
264 secmem_set_flags( unsigned flags )
265 {
266     int was_susp = suspend_warning;
267
268     no_warning = flags & 1;
269     suspend_warning = flags & 2;
270
271     /* and now issue the warning if it is not longer suspended */
272     if( was_susp && !suspend_warning && show_warning ) {
273         show_warning = 0;
274         print_warn();
275     }
276 }
277
278 unsigned
279 secmem_get_flags(void)
280 {
281     unsigned flags;
282
283     flags  = no_warning      ? 1:0;
284     flags |= suspend_warning ? 2:0;
285     return flags;
286 }
287
288 void
289 secmem_init( size_t n )
290 {
291     if( !n ) {
292 #ifndef __riscos__
293       #ifdef USE_CAPABILITIES
294         /* drop all capabilities */
295         cap_set_proc( cap_from_text("all-eip") );
296
297       #elif !defined(HAVE_DOSISH_SYSTEM)
298         uid_t uid;
299
300         disable_secmem=1;
301         uid = getuid();
302         if( uid != geteuid() ) {
303             if( setuid( uid ) || getuid() != geteuid() || !setuid(0) )
304                 log_fatal("failed to drop setuid\n" );
305         }
306       #endif
307 #endif /* !__riscos__ */
308     }
309     else {
310         if( n < DEFAULT_POOLSIZE )
311             n = DEFAULT_POOLSIZE;
312         if( !pool_okay )
313             init_pool(n);
314         else
315             log_error("Oops, secure memory pool already initialized\n");
316     }
317 }
318
319
320 void *
321 secmem_malloc( size_t size )
322 {
323     MEMBLOCK *mb, *mb2;
324     int compressed=0;
325
326     if( !pool_okay ) {
327         log_info(
328          _("operation is not possible without initialized secure memory\n"));
329         log_info(_("(you may have used the wrong program for this task)\n"));
330         exit(2);
331     }
332     if( show_warning && !suspend_warning ) {
333         show_warning = 0;
334         print_warn();
335     }
336
337     /* blocks are always a multiple of 32 */
338     size += sizeof(MEMBLOCK);
339     size = ((size + 31) / 32) * 32;
340
341   retry:
342     /* try to get it from the used blocks */
343     for(mb = unused_blocks,mb2=NULL; mb; mb2=mb, mb = mb->u.next )
344         if( mb->size >= size ) {
345             if( mb2 )
346                 mb2->u.next = mb->u.next;
347             else
348                 unused_blocks = mb->u.next;
349             goto leave;
350         }
351     /* allocate a new block */
352     if( (poollen + size <= poolsize) ) {
353         mb = (void*)((char*)pool + poollen);
354         poollen += size;
355         mb->size = size;
356     }
357     else if( !compressed ) {
358         compressed=1;
359         compress_pool();
360         goto retry;
361     }
362     else
363         return NULL;
364
365   leave:
366     cur_alloced += mb->size;
367     cur_blocks++;
368     if( cur_alloced > max_alloced )
369         max_alloced = cur_alloced;
370     if( cur_blocks > max_blocks )
371         max_blocks = cur_blocks;
372
373     return &mb->u.aligned.c;
374 }
375
376
377 void *
378 secmem_realloc( void *p, size_t newsize )
379 {
380     MEMBLOCK *mb;
381     size_t size;
382     void *a;
383
384     mb = (MEMBLOCK*)((char*)p - ((size_t) &((MEMBLOCK*)0)->u.aligned.c));
385     size = mb->size;
386     if( newsize < size )
387         return p; /* it is easier not to shrink the memory */
388     a = secmem_malloc( newsize );
389     if ( a ) {
390         memcpy(a, p, size);
391         memset((char*)a+size, 0, newsize-size);
392         secmem_free(p);
393     }
394     return a;
395 }
396
397
398 void
399 secmem_free( void *a )
400 {
401     MEMBLOCK *mb;
402     size_t size;
403
404     if( !a )
405         return;
406
407     mb = (MEMBLOCK*)((char*)a - ((size_t) &((MEMBLOCK*)0)->u.aligned.c));
408     size = mb->size;
409     /* This does not make much sense: probably this memory is held in the
410      * cache. We do it anyway: */
411     wipememory2(mb, 0xff, size );
412     wipememory2(mb, 0xaa, size );
413     wipememory2(mb, 0x55, size );
414     wipememory2(mb, 0x00, size );
415     mb->size = size;
416     mb->u.next = unused_blocks;
417     unused_blocks = mb;
418     cur_blocks--;
419     cur_alloced -= size;
420 }
421
422 int
423 m_is_secure( const void *p )
424 {
425     return p >= pool && p < (void*)((char*)pool+poolsize);
426 }
427
428
429
430 /****************
431  * Warning:  This code might be called by an interrupt handler
432  *           and frankly, there should really be such a handler,
433  *           to make sure that the memory is wiped out.
434  *           We hope that the OS wipes out mlocked memory after
435  *           receiving a SIGKILL - it really should do so, otherwise
436  *           there is no chance to get the secure memory cleaned.
437  */
438 void
439 secmem_term()
440 {
441     if( !pool_okay )
442         return;
443
444     wipememory2( pool, 0xff, poolsize);
445     wipememory2( pool, 0xaa, poolsize);
446     wipememory2( pool, 0x55, poolsize);
447     wipememory2( pool, 0x00, poolsize);
448   #ifdef HAVE_MMAP
449     if( pool_is_mmapped )
450         munmap( pool, poolsize );
451   #endif
452     pool = NULL;
453     pool_okay = 0;
454     poolsize=0;
455     poollen=0;
456     unused_blocks=NULL;
457 }
458
459
460 void
461 secmem_dump_stats()
462 {
463     if( disable_secmem )
464         return;
465     fprintf(stderr,
466                 "secmem usage: %u/%u bytes in %u/%u blocks of pool %lu/%lu\n",
467                 cur_alloced, max_alloced, cur_blocks, max_blocks,
468                 (ulong)poollen, (ulong)poolsize );
469 }
470