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