2003-07-30 Moritz Schulte <moritz@g10code.com>
[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           )
243         log_error ("can't lock memory: %s\n", strerror (err));
244       show_warning = 1;
245     }
246
247 #elif defined(HAVE_MLOCK)
248   uid_t uid;
249   int err;
250
251   uid = getuid ();
252
253 #ifdef HAVE_BROKEN_MLOCK
254   if (uid)
255     {
256       errno = EPERM;
257       err = errno;
258     }
259   else
260     {
261       err = mlock (p, n);
262       if (err && errno)
263         err = errno;
264     }
265 #else
266   err = mlock (p, n);
267   if (err && errno)
268     err = errno;
269 #endif
270
271   if (uid && ! geteuid ())
272     {
273       /* check that we really dropped the privs.
274        * Note: setuid(0) should always fail */
275       if (setuid (uid) || getuid () != geteuid () || !setuid (0))
276         log_fatal ("failed to reset uid: %s\n", strerror (errno));
277     }
278
279   if (err)
280     {
281       if (errno != EPERM
282 #ifdef EAGAIN                   /* OpenBSD returns this */
283           && errno != EAGAIN
284 #endif
285 #ifdef ENOSYS                   /* Some SCOs return this (function not implemented) */
286           && errno != ENOSYS
287 #endif
288           )
289         log_error ("can't lock memory: %s\n", strerror (err));
290       show_warning = 1;
291     }
292
293 #elif defined ( __QNX__ )
294   /* QNX does not page at all, so the whole secure memory stuff does
295    * not make much sense.  However it is still of use because it
296    * wipes out the memory on a free().
297    * Therefore it is sufficient to suppress the warning
298    */
299 #else
300   log_info ("Please note that you don't have secure memory on this system\n");
301 #endif
302 }
303
304 /* Initialize POOL.  */
305 static void
306 init_pool (size_t n)
307 {
308   size_t pgsize;
309   memblock_t *mb;
310
311   pool_size = n;
312
313   if (disable_secmem)
314     log_bug ("secure memory is disabled");
315
316 #ifdef HAVE_GETPAGESIZE
317   pgsize = getpagesize ();
318 #else
319   pgsize = DEFAULT_PAGE_SIZE;
320 #endif
321
322 #if HAVE_MMAP
323   pool_size = (pool_size + pgsize - 1) & ~(pgsize - 1);
324 #ifdef MAP_ANONYMOUS
325   pool = mmap (0, pool_size, PROT_READ | PROT_WRITE,
326                MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
327 #else /* map /dev/zero instead */
328   {
329     int fd;
330
331     fd = open ("/dev/zero", O_RDWR);
332     if (fd == -1)
333       {
334         log_error ("can't open /dev/zero: %s\n", strerror (errno));
335         pool = (void *) -1;
336       }
337     else
338       {
339         pool = mmap (0, pool_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
340       }
341   }
342 #endif
343   if (pool == (void *) -1)
344     log_info ("can't mmap pool of %u bytes: %s - using malloc\n",
345               (unsigned) pool_size, strerror (errno));
346   else
347     {
348       pool_is_mmapped = 1;
349       pool_okay = 1;
350     }
351
352 #endif
353   if (!pool_okay)
354     {
355       pool = malloc (pool_size);
356       if (!pool)
357         log_fatal ("can't allocate memory pool of %u bytes\n",
358                    (unsigned) pool_size);
359       else
360         pool_okay = 1;
361     }
362
363   /* Initialize first memory block.  */
364   mb = (memblock_t *) pool;
365   mb->size = pool_size;
366   mb->flags = 0;
367 }
368
369 void
370 _gcry_secmem_set_flags (unsigned flags)
371 {
372   int was_susp;
373
374   SECMEM_LOCK;
375
376   was_susp = suspend_warning;
377   no_warning = flags & GCRY_SECMEM_FLAG_NO_WARNING;
378   suspend_warning = flags & GCRY_SECMEM_FLAG_SUSPEND_WARNING;
379
380   /* and now issue the warning if it is not longer suspended */
381   if (was_susp && !suspend_warning && show_warning)
382     {
383       show_warning = 0;
384       print_warn ();
385     }
386
387   SECMEM_UNLOCK;
388 }
389
390 unsigned
391 _gcry_secmem_get_flags (void)
392 {
393   unsigned flags;
394
395   SECMEM_LOCK;
396
397   flags = no_warning ? GCRY_SECMEM_FLAG_NO_WARNING : 0;
398   flags |= suspend_warning ? GCRY_SECMEM_FLAG_SUSPEND_WARNING : 0;
399
400   SECMEM_UNLOCK;
401
402   return flags;
403 }
404
405 /* Initialize the secure memory system.  If running with the necessary
406    privileges, the secure memory pool will be locked into the core in
407    order to prevent page-outs of the data.  Furthermore allocated
408    secure memory will be wiped out when released.  */
409 void
410 _gcry_secmem_init (size_t n)
411 {
412   SECMEM_LOCK;
413
414   if (!n)
415     {
416 #ifdef USE_CAPABILITIES
417       /* drop all capabilities */
418       cap_set_proc (cap_from_text ("all-eip"));
419
420 #elif !defined(HAVE_DOSISH_SYSTEM)
421       uid_t uid;
422
423       disable_secmem = 1;
424       uid = getuid ();
425       if (uid != geteuid ())
426         {
427           if (setuid (uid) || getuid () != geteuid () || !setuid (0))
428             log_fatal ("failed to drop setuid\n");
429         }
430 #endif
431     }
432   else
433     {
434       if (n < DEFAULT_POOL_SIZE)
435         n = DEFAULT_POOL_SIZE;
436       if (! pool_okay)
437         {
438           init_pool (n);
439           if (! geteuid ())
440             lock_pool (pool, n);
441           else
442             log_info ("Secure memory is not locked into core\n");
443         }
444       else
445         log_error ("Oops, secure memory pool already initialized\n");
446     }
447
448   SECMEM_UNLOCK;
449 }
450
451
452 static void *
453 _gcry_secmem_malloc_internal (size_t size)
454 {
455   memblock_t *mb;
456
457   if (!pool_okay)
458     {
459       log_info (_
460                 ("operation is not possible without initialized secure memory\n"));
461       log_info (_("(you may have used the wrong program for this task)\n"));
462       exit (2);
463     }
464   if (show_warning && !suspend_warning)
465     {
466       show_warning = 0;
467       print_warn ();
468     }
469
470   /* blocks are always a multiple of 32 */
471   size = ((size + 31) / 32) * 32;
472
473   mb = mb_get_new ((memblock_t *) pool, size);
474   if (mb)
475     stats_update (size, 0);
476
477   return mb ? &mb->aligned.c : NULL;
478 }
479
480 void *
481 _gcry_secmem_malloc (size_t size)
482 {
483   void *p;
484
485   SECMEM_LOCK;
486   p = _gcry_secmem_malloc_internal (size);
487   SECMEM_UNLOCK;
488   
489   return p;
490 }
491
492 static void
493 _gcry_secmem_free_internal (void *a)
494 {
495   memblock_t *mb;
496   int size;
497
498   if (!a)
499     return;
500
501   mb = ADDR_TO_BLOCK (a);
502   size = mb->size;
503
504   /* This does not make much sense: probably this memory is held in the
505    * cache. We do it anyway: */
506 #define MB_WIPE_OUT(byte) \
507   memset ((memblock_t *) ((char *) mb + BLOCK_HEAD_SIZE), (byte), size);
508
509   MB_WIPE_OUT (0xff);
510   MB_WIPE_OUT (0xaa);
511   MB_WIPE_OUT (0x55);
512   MB_WIPE_OUT (0x00);
513
514   stats_update (0, size);
515
516   mb->flags &= ~MB_FLAG_ACTIVE;
517
518   /* Update stats.  */
519
520   mb_merge (mb);
521 }
522
523 /* Wipe out and release memory.  */
524 void
525 _gcry_secmem_free (void *a)
526 {
527   SECMEM_LOCK;
528   _gcry_secmem_free_internal (a);
529   SECMEM_UNLOCK;
530 }
531
532 /* Realloc memory.  */
533 void *
534 _gcry_secmem_realloc (void *p, size_t newsize)
535 {
536   memblock_t *mb;
537   size_t size;
538   void *a;
539
540   SECMEM_LOCK;
541
542   mb = (memblock_t *) ((char *) p - ((size_t) & ((memblock_t *) 0)->aligned.c));
543   size = mb->size;
544   if (newsize < size)
545     return p;                   /* it is easier not to shrink the memory */
546   a = _gcry_secmem_malloc_internal (newsize);
547   if (a)
548     {
549       memcpy (a, p, size);
550       memset ((char *) a + size, 0, newsize - size);
551       _gcry_secmem_free_internal (p);
552     }
553
554   SECMEM_UNLOCK;
555
556   return a;
557 }
558
559 int
560 _gcry_private_is_secure (const void *p)
561 {
562   int ret = 0;
563
564   SECMEM_LOCK;
565
566   if (pool_okay && BLOCK_VALID (ADDR_TO_BLOCK (p)))
567     ret = 1;
568
569   SECMEM_UNLOCK;
570
571   return ret;
572 }
573
574
575 /****************
576  * Warning:  This code might be called by an interrupt handler
577  *           and frankly, there should really be such a handler,
578  *           to make sure that the memory is wiped out.
579  *           We hope that the OS wipes out mlocked memory after
580  *           receiving a SIGKILL - it really should do so, otherwise
581  *           there is no chance to get the secure memory cleaned.
582  */
583 void
584 _gcry_secmem_term ()
585 {
586   if (!pool_okay)
587     return;
588
589   memset (pool, 0xff, pool_size);
590   memset (pool, 0xaa, pool_size);
591   memset (pool, 0x55, pool_size);
592   memset (pool, 0x00, pool_size);
593 #if HAVE_MMAP
594   if (pool_is_mmapped)
595     munmap (pool, pool_size);
596 #endif
597   pool = NULL;
598   pool_okay = 0;
599   pool_size = 0;
600 }
601
602
603 void
604 _gcry_secmem_dump_stats ()
605 {
606 #if 1 
607   SECMEM_LOCK;
608
609  if (pool_okay)
610     log_info ("secmem usage: %u/%u bytes in %u blocks\n",
611               cur_alloced, pool_size, cur_blocks);
612   SECMEM_UNLOCK;
613 #else
614   memblock_t *mb;
615   int i;
616
617   SECMEM_LOCK;
618
619   for (i = 0, mb = (memblock_t *) pool;
620        BLOCK_VALID (mb);
621        mb = mb_get_next (mb), i++)
622     log_info ("SECMEM: [%s] block: %i; size: %i\n",
623               (mb->flags & MB_FLAG_ACTIVE) ? "used" : "free",
624               i,
625               mb->size);
626   SECMEM_UNLOCK;
627 #endif
628 }