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