(lock_pool): Don't print the warning for certain
[libgcrypt.git] / src / secmem.c
1 /* secmem.c  -  memory allocation from a secure heap
2  * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
3  *
4  * This file is part of Libgcrypt.
5  *
6  * Libgcrypt is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU Lesser general Public License as
8  * published by the Free Software Foundation; either version 2.1 of
9  * the License, or (at your option) any later version.
10  *
11  * Libgcrypt 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 Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License 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 #include <stddef.h>
29
30 #if defined(HAVE_MLOCK) || defined(HAVE_MMAP)
31 #include <sys/mman.h>
32 #include <sys/types.h>
33 #include <fcntl.h>
34 #ifdef USE_CAPABILITIES
35 #include <sys/capability.h>
36 #endif
37 #endif
38
39 #include "ath.h"
40 #include "g10lib.h"
41 #include "secmem.h"
42
43 #if defined (MAP_ANON) && ! defined (MAP_ANONYMOUS)
44 #define MAP_ANONYMOUS MAP_ANON
45 #endif
46
47 #define DEFAULT_POOL_SIZE 16384
48 #define DEFAULT_PAGE_SIZE 4096
49
50 typedef struct memblock
51 {
52   unsigned size;                /* Size of the memory available to the
53                                    user.  */
54   int flags;                    /* See below.  */
55   PROPERLY_ALIGNED_TYPE aligned;
56 } memblock_t;
57
58 /* This flag specifies that the memory block is in use.  */
59 #define MB_FLAG_ACTIVE 1 << 0
60
61 /* The pool of secure memory.  */
62 static void *pool;
63
64 /* Size of POOL in bytes.  */
65 static size_t pool_size;
66
67 /* True, if the memory pool is ready for use.  May be checked in an
68    atexit function.  */
69 static volatile int pool_okay;
70
71 /* True, if the memory pool is mmapped.  */
72 static volatile int pool_is_mmapped;
73
74 /* FIXME?  */
75 static int disable_secmem;
76 static int show_warning;
77 static int no_warning;
78 static int suspend_warning;
79
80 /* Stats.  */
81 static unsigned int cur_alloced, cur_blocks;
82
83 /* Lock protecting accesses to the memory pool.  */
84 static ath_mutex_t secmem_lock;
85
86 /* Convenient macros.  */
87 #define SECMEM_LOCK   ath_mutex_lock   (&secmem_lock)
88 #define SECMEM_UNLOCK ath_mutex_unlock (&secmem_lock)
89
90 /* The size of the memblock structure; this does not include the
91    memory that is available to the user.  */
92 #define BLOCK_HEAD_SIZE \
93   offsetof (memblock_t, aligned)
94
95 /* Convert an address into the according memory block structure.  */
96 #define ADDR_TO_BLOCK(addr) \
97   (memblock_t *) ((char *) addr - BLOCK_HEAD_SIZE)
98
99 /* Check wether MB is a valid block.  */
100 #define BLOCK_VALID(mb) \
101   (((char *) mb - (char *) pool) < pool_size)
102
103 /* Update the stats.  */
104 static void
105 stats_update (size_t add, size_t sub)
106 {
107   if (add)
108     {
109       cur_alloced += add;
110       cur_blocks++;
111     }
112   if (sub)
113     {
114       cur_alloced -= sub;
115       cur_blocks--;
116     }
117 }
118
119 /* Return the block following MB or NULL, if MB is the last block.  */
120 static memblock_t *
121 mb_get_next (memblock_t *mb)
122 {
123   memblock_t *mb_next;
124
125   mb_next = (memblock_t *) ((char *) mb + BLOCK_HEAD_SIZE + mb->size);
126   
127   if (! BLOCK_VALID (mb_next))
128     mb_next = NULL;
129
130   return mb_next;
131 }
132
133 /* Return the block preceeding MB or NULL, if MB is the first
134    block.  */
135 static memblock_t *
136 mb_get_prev (memblock_t *mb)
137 {
138   memblock_t *mb_prev, *mb_next;
139
140   if (mb == pool)
141     mb_prev = NULL;
142   else
143     {
144       mb_prev = (memblock_t *) pool;
145       while (1)
146         {
147           mb_next = mb_get_next (mb_prev);
148           if (mb_next == mb)
149             break;
150           else
151             mb_prev = mb_next;
152         }
153     }
154
155   return mb_prev;
156 }
157
158 /* If the preceeding block of MB and/or the following block of MB
159    exist and are not active, merge them to form a bigger block.  */
160 static void
161 mb_merge (memblock_t *mb)
162 {
163   memblock_t *mb_prev, *mb_next;
164
165   mb_prev = mb_get_prev (mb);
166   mb_next = mb_get_next (mb);
167
168   if (mb_prev && (! (mb_prev->flags & MB_FLAG_ACTIVE)))
169     {
170       mb_prev->size += BLOCK_HEAD_SIZE + mb->size;
171       mb = mb_prev;
172     }
173   if (mb_next && (! (mb_next->flags & MB_FLAG_ACTIVE)))
174     mb->size += BLOCK_HEAD_SIZE + mb_next->size;
175 }
176
177 /* Return a new block, which can hold SIZE bytes.  */
178 static memblock_t *
179 mb_get_new (memblock_t *pool, size_t size)
180 {
181   memblock_t *mb, *mb_split;
182   
183   for (mb = pool; BLOCK_VALID (mb); mb = mb_get_next (mb))
184     if (! (mb->flags & MB_FLAG_ACTIVE) && mb->size >= size)
185       {
186         /* Found a free block.  */
187         mb->flags |= MB_FLAG_ACTIVE;
188
189         if (mb->size - size > BLOCK_HEAD_SIZE)
190           {
191             /* Split block.  */
192           
193             mb_split = (memblock_t *) (((char *) mb) + BLOCK_HEAD_SIZE + size);
194             mb_split->size = mb->size - size - BLOCK_HEAD_SIZE;
195             mb_split->flags = 0;
196
197             mb->size = size;
198
199             mb_merge (mb_split);
200
201           }
202
203         break;
204       }
205
206   if (! BLOCK_VALID (mb))
207     mb = NULL;
208
209   return mb;
210 }
211
212 /* Print a warning message.  */
213 static void
214 print_warn (void)
215 {
216   if (!no_warning)
217     log_info (_("Warning: using insecure memory!\n"));
218 }
219
220 /* Lock the memory pages into core and drop privileges.  */
221 static void
222 lock_pool (void *p, size_t n)
223 {
224 #if defined(USE_CAPABILITIES) && defined(HAVE_MLOCK)
225   int err;
226
227   cap_set_proc (cap_from_text ("cap_ipc_lock+ep"));
228   err = mlock (p, n);
229   if (err && errno)
230     err = errno;
231   cap_set_proc (cap_from_text ("cap_ipc_lock+p"));
232
233   if (err)
234     {
235       if (errno != EPERM
236 #ifdef EAGAIN   /* OpenBSD returns this */
237           && errno != EAGAIN
238 #endif
239 #ifdef ENOSYS   /* Some SCOs return this (function not implemented) */
240           && errno != ENOSYS
241 #endif
242 #ifdef ENOMEM  /* Linux might return this. */
243             && errno != ENOMEM
244 #endif
245           )
246         log_error ("can't lock memory: %s\n", strerror (err));
247       show_warning = 1;
248     }
249
250 #elif defined(HAVE_MLOCK)
251   uid_t uid;
252   int err;
253
254   uid = getuid ();
255
256 #ifdef HAVE_BROKEN_MLOCK
257   /* Under HP/UX mlock segfaults if called by non-root.  Note, we have
258      noch checked whether mlock does really work under AIX where we
259      also detected a broken nlock.  Note further, that using plock ()
260      is not a good idea under AIX. */ 
261   if (uid)
262     {
263       errno = EPERM;
264       err = errno;
265     }
266   else
267     {
268       err = mlock (p, n);
269       if (err && errno)
270         err = errno;
271     }
272 #else /* !HAVE_BROKEN_MLOCK */
273   err = mlock (p, n);
274   if (err && errno)
275     err = errno;
276 #endif /* !HAVE_BROKEN_MLOCK */
277
278   if (uid && ! geteuid ())
279     {
280       /* check that we really dropped the privs.
281        * Note: setuid(0) should always fail */
282       if (setuid (uid) || getuid () != geteuid () || !setuid (0))
283         log_fatal ("failed to reset uid: %s\n", strerror (errno));
284     }
285
286   if (err)
287     {
288       if (errno != EPERM
289 #ifdef EAGAIN   /* OpenBSD returns this. */
290           && errno != EAGAIN
291 #endif
292 #ifdef ENOSYS   /* Some SCOs return this (function not implemented). */
293           && errno != ENOSYS
294 #endif
295 #ifdef ENOMEM  /* Linux might return this. */
296             && errno != ENOMEM
297 #endif
298           )
299         log_error ("can't lock memory: %s\n", strerror (err));
300       show_warning = 1;
301     }
302
303 #elif defined ( __QNX__ )
304   /* QNX does not page at all, so the whole secure memory stuff does
305    * not make much sense.  However it is still of use because it
306    * wipes out the memory on a free().
307    * Therefore it is sufficient to suppress the warning
308    */
309 #elif defined (HAVE_DOSISH_SYSTEM) || defined (__CYGWIN__)
310     /* It does not make sense to print such a warning, given the fact that 
311      * this whole Windows !@#$% and their user base are inherently insecure
312      */
313 #elif defined (__riscos__)
314     /* no virtual memory on RISC OS, so no pages are swapped to disc,
315      * besides we don't have mmap, so we don't use it! ;-)
316      * But don't complain, as explained above.
317      */
318 #else
319   log_info ("Please note that you don't have secure memory on this system\n");
320 #endif
321 }
322
323 /* Initialize POOL.  */
324 static void
325 init_pool (size_t n)
326 {
327   size_t pgsize;
328   memblock_t *mb;
329
330   pool_size = n;
331
332   if (disable_secmem)
333     log_bug ("secure memory is disabled");
334
335 #ifdef HAVE_GETPAGESIZE
336   pgsize = getpagesize ();
337 #else
338   pgsize = DEFAULT_PAGE_SIZE;
339 #endif
340
341 #if HAVE_MMAP
342   pool_size = (pool_size + pgsize - 1) & ~(pgsize - 1);
343 #ifdef MAP_ANONYMOUS
344   pool = mmap (0, pool_size, PROT_READ | PROT_WRITE,
345                MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
346 #else /* map /dev/zero instead */
347   {
348     int fd;
349
350     fd = open ("/dev/zero", O_RDWR);
351     if (fd == -1)
352       {
353         log_error ("can't open /dev/zero: %s\n", strerror (errno));
354         pool = (void *) -1;
355       }
356     else
357       {
358         pool = mmap (0, pool_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
359       }
360   }
361 #endif
362   if (pool == (void *) -1)
363     log_info ("can't mmap pool of %u bytes: %s - using malloc\n",
364               (unsigned) pool_size, strerror (errno));
365   else
366     {
367       pool_is_mmapped = 1;
368       pool_okay = 1;
369     }
370
371 #endif
372   if (!pool_okay)
373     {
374       pool = malloc (pool_size);
375       if (!pool)
376         log_fatal ("can't allocate memory pool of %u bytes\n",
377                    (unsigned) pool_size);
378       else
379         pool_okay = 1;
380     }
381
382   /* Initialize first memory block.  */
383   mb = (memblock_t *) pool;
384   mb->size = pool_size;
385   mb->flags = 0;
386 }
387
388 void
389 _gcry_secmem_set_flags (unsigned flags)
390 {
391   int was_susp;
392
393   SECMEM_LOCK;
394
395   was_susp = suspend_warning;
396   no_warning = flags & GCRY_SECMEM_FLAG_NO_WARNING;
397   suspend_warning = flags & GCRY_SECMEM_FLAG_SUSPEND_WARNING;
398
399   /* and now issue the warning if it is not longer suspended */
400   if (was_susp && !suspend_warning && show_warning)
401     {
402       show_warning = 0;
403       print_warn ();
404     }
405
406   SECMEM_UNLOCK;
407 }
408
409 unsigned
410 _gcry_secmem_get_flags (void)
411 {
412   unsigned flags;
413
414   SECMEM_LOCK;
415
416   flags = no_warning ? GCRY_SECMEM_FLAG_NO_WARNING : 0;
417   flags |= suspend_warning ? GCRY_SECMEM_FLAG_SUSPEND_WARNING : 0;
418
419   SECMEM_UNLOCK;
420
421   return flags;
422 }
423
424 /* Initialize the secure memory system.  If running with the necessary
425    privileges, the secure memory pool will be locked into the core in
426    order to prevent page-outs of the data.  Furthermore allocated
427    secure memory will be wiped out when released.  */
428 void
429 _gcry_secmem_init (size_t n)
430 {
431   SECMEM_LOCK;
432
433   if (!n)
434     {
435 #ifdef USE_CAPABILITIES
436       /* drop all capabilities */
437       cap_set_proc (cap_from_text ("all-eip"));
438
439 #elif !defined(HAVE_DOSISH_SYSTEM)
440       uid_t uid;
441
442       disable_secmem = 1;
443       uid = getuid ();
444       if (uid != geteuid ())
445         {
446           if (setuid (uid) || getuid () != geteuid () || !setuid (0))
447             log_fatal ("failed to drop setuid\n");
448         }
449 #endif
450     }
451   else
452     {
453       if (n < DEFAULT_POOL_SIZE)
454         n = DEFAULT_POOL_SIZE;
455       if (! pool_okay)
456         {
457           init_pool (n);
458           if (! geteuid ())
459             lock_pool (pool, n);
460           else
461             log_info ("Secure memory is not locked into core\n");
462         }
463       else
464         log_error ("Oops, secure memory pool already initialized\n");
465     }
466
467   SECMEM_UNLOCK;
468 }
469
470
471 static void *
472 _gcry_secmem_malloc_internal (size_t size)
473 {
474   memblock_t *mb;
475
476   if (!pool_okay)
477     {
478       log_info (_
479                 ("operation is not possible without initialized secure memory\n"));
480       log_info (_("(you may have used the wrong program for this task)\n"));
481       exit (2);
482     }
483   if (show_warning && !suspend_warning)
484     {
485       show_warning = 0;
486       print_warn ();
487     }
488
489   /* blocks are always a multiple of 32 */
490   size = ((size + 31) / 32) * 32;
491
492   mb = mb_get_new ((memblock_t *) pool, size);
493   if (mb)
494     stats_update (size, 0);
495
496   return mb ? &mb->aligned.c : NULL;
497 }
498
499 void *
500 _gcry_secmem_malloc (size_t size)
501 {
502   void *p;
503
504   SECMEM_LOCK;
505   p = _gcry_secmem_malloc_internal (size);
506   SECMEM_UNLOCK;
507   
508   return p;
509 }
510
511 static void
512 _gcry_secmem_free_internal (void *a)
513 {
514   memblock_t *mb;
515   int size;
516
517   if (!a)
518     return;
519
520   mb = ADDR_TO_BLOCK (a);
521   size = mb->size;
522
523   /* This does not make much sense: probably this memory is held in the
524    * cache. We do it anyway: */
525 #define MB_WIPE_OUT(byte) \
526   memset ((memblock_t *) ((char *) mb + BLOCK_HEAD_SIZE), (byte), size);
527
528   MB_WIPE_OUT (0xff);
529   MB_WIPE_OUT (0xaa);
530   MB_WIPE_OUT (0x55);
531   MB_WIPE_OUT (0x00);
532
533   stats_update (0, size);
534
535   mb->flags &= ~MB_FLAG_ACTIVE;
536
537   /* Update stats.  */
538
539   mb_merge (mb);
540 }
541
542 /* Wipe out and release memory.  */
543 void
544 _gcry_secmem_free (void *a)
545 {
546   SECMEM_LOCK;
547   _gcry_secmem_free_internal (a);
548   SECMEM_UNLOCK;
549 }
550
551 /* Realloc memory.  */
552 void *
553 _gcry_secmem_realloc (void *p, size_t newsize)
554 {
555   memblock_t *mb;
556   size_t size;
557   void *a;
558
559   SECMEM_LOCK;
560
561   mb = (memblock_t *) ((char *) p - ((size_t) &((memblock_t *) 0)->aligned.c));
562   size = mb->size;
563   if (newsize < size)
564     {
565       SECMEM_UNLOCK;
566       /* It is easier to not shrink the memory.  */
567       a = p;
568     }
569   else
570     {
571       a = _gcry_secmem_malloc_internal (newsize);
572       if (a)
573         {
574           memcpy (a, p, size);
575           memset ((char *) a + size, 0, newsize - size);
576           _gcry_secmem_free_internal (p);
577         }
578     }
579
580   SECMEM_UNLOCK;
581
582   return a;
583 }
584
585 int
586 _gcry_private_is_secure (const void *p)
587 {
588   int ret = 0;
589
590   SECMEM_LOCK;
591
592   if (pool_okay && BLOCK_VALID (ADDR_TO_BLOCK (p)))
593     ret = 1;
594
595   SECMEM_UNLOCK;
596
597   return ret;
598 }
599
600
601 /****************
602  * Warning:  This code might be called by an interrupt handler
603  *           and frankly, there should really be such a handler,
604  *           to make sure that the memory is wiped out.
605  *           We hope that the OS wipes out mlocked memory after
606  *           receiving a SIGKILL - it really should do so, otherwise
607  *           there is no chance to get the secure memory cleaned.
608  */
609 void
610 _gcry_secmem_term ()
611 {
612   if (!pool_okay)
613     return;
614
615   memset (pool, 0xff, pool_size);
616   memset (pool, 0xaa, pool_size);
617   memset (pool, 0x55, pool_size);
618   memset (pool, 0x00, pool_size);
619 #if HAVE_MMAP
620   if (pool_is_mmapped)
621     munmap (pool, pool_size);
622 #endif
623   pool = NULL;
624   pool_okay = 0;
625   pool_size = 0;
626 }
627
628
629 void
630 _gcry_secmem_dump_stats ()
631 {
632 #if 1 
633   SECMEM_LOCK;
634
635  if (pool_okay)
636     log_info ("secmem usage: %u/%lu bytes in %u blocks\n",
637               cur_alloced, (unsigned long)pool_size, cur_blocks);
638   SECMEM_UNLOCK;
639 #else
640   memblock_t *mb;
641   int i;
642
643   SECMEM_LOCK;
644
645   for (i = 0, mb = (memblock_t *) pool;
646        BLOCK_VALID (mb);
647        mb = mb_get_next (mb), i++)
648     log_info ("SECMEM: [%s] block: %i; size: %i\n",
649               (mb->flags & MB_FLAG_ACTIVE) ? "used" : "free",
650               i,
651               mb->size);
652   SECMEM_UNLOCK;
653 #endif
654 }