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