1/* stdmem.c  -	private memory allocator
2 * Copyright (C) 1998, 2000, 2002, 2005, 2008 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, see <http://www.gnu.org/licenses/>.
18 */
19
20/*
21 * Description of the layered memory management in Libgcrypt:
22 *
23 *                                  [User]
24 *                                    |
25 *                                    |
26 *                                   \ /
27 *                   global.c: [MM entrance points]   -----> [user callbacks]
28 *                               |          |
29 *                               |          |
30 *                              \ /        \ /
31 *
32 *      stdmem.c: [non-secure handlers] [secure handlers]
33 *
34 *                               |         |
35 *                               |         |
36 *                              \ /       \ /
37 *
38 *                  stdmem.c: [ memory guard ]
39 *
40 *                               |         |
41 *                               |         |
42 *                              \ /       \ /
43 *
44 *           libc: [ MM functions ]     secmem.c: [ secure MM functions]
45 */
46
47#include <config.h>
48#include <stdio.h>
49#include <stdlib.h>
50#include <string.h>
51#include <stdarg.h>
52#include <errno.h>
53
54#include "g10lib.h"
55#include "stdmem.h"
56#include "secmem.h"
57
58
59
60#define MAGIC_NOR_BYTE 0x55
61#define MAGIC_SEC_BYTE 0xcc
62#define MAGIC_END_BYTE 0xaa
63
64#if SIZEOF_UNSIGNED_LONG == 8
65#define EXTRA_ALIGN 4
66#else
67#define EXTRA_ALIGN 0
68#endif
69
70
71static int use_m_guard = 0;
72
73/****************
74 * Warning: Never use this function after any of the functions
75 * here have been used.
76 */
77void
78_gcry_private_enable_m_guard (void)
79{
80  use_m_guard = 1;
81}
82
83
84/*
85 * Allocate memory of size n.
86 * Return NULL if we are out of memory.
87 */
88void *
89_gcry_private_malloc (size_t n)
90{
91  if (!n)
92    {
93      gpg_err_set_errno (EINVAL);
94      return NULL; /* Allocating 0 bytes is undefined - we better return
95                      an error to detect such coding errors.  */
96    }
97
98  if (use_m_guard)
99    {
100      char *p;
101
102      if ( !(p = malloc (n + EXTRA_ALIGN+5)) )
103        return NULL;
104      ((byte*)p)[EXTRA_ALIGN+0] = n;
105      ((byte*)p)[EXTRA_ALIGN+1] = n >> 8 ;
106      ((byte*)p)[EXTRA_ALIGN+2] = n >> 16 ;
107      ((byte*)p)[EXTRA_ALIGN+3] = MAGIC_NOR_BYTE;
108      p[4+EXTRA_ALIGN+n] = MAGIC_END_BYTE;
109      return p+EXTRA_ALIGN+4;
110    }
111  else
112    {
113      return malloc( n );
114    }
115}
116
117
118/*
119 * Allocate memory of size N from the secure memory pool.  Return NULL
120 * if we are out of memory.
121 */
122void *
123_gcry_private_malloc_secure (size_t n)
124{
125  if (!n)
126    {
127      gpg_err_set_errno (EINVAL);
128      return NULL; /* Allocating 0 bytes is undefined - better return an
129                      error to detect such coding errors.  */
130    }
131
132  if (use_m_guard)
133    {
134      char *p;
135
136      if ( !(p = _gcry_secmem_malloc (n +EXTRA_ALIGN+ 5)) )
137        return NULL;
138      ((byte*)p)[EXTRA_ALIGN+0] = n;
139      ((byte*)p)[EXTRA_ALIGN+1] = n >> 8 ;
140      ((byte*)p)[EXTRA_ALIGN+2] = n >> 16 ;
141      ((byte*)p)[EXTRA_ALIGN+3] = MAGIC_SEC_BYTE;
142      p[4+EXTRA_ALIGN+n] = MAGIC_END_BYTE;
143      return p+EXTRA_ALIGN+4;
144    }
145  else
146    {
147      return _gcry_secmem_malloc( n );
148    }
149}
150
151
152/*
153 * Realloc and clear the old space
154 * Return NULL if there is not enough memory.
155 */
156void *
157_gcry_private_realloc ( void *a, size_t n )
158{
159  if (use_m_guard)
160    {
161      unsigned char *p = a;
162      char *b;
163      size_t len;
164
165      if (!a)
166        return _gcry_private_malloc(n);
167
168      _gcry_private_check_heap(p);
169      len  = p[-4];
170      len |= p[-3] << 8;
171      len |= p[-2] << 16;
172      if( len >= n ) /* We don't shrink for now. */
173        return a;
174      if (p[-1] == MAGIC_SEC_BYTE)
175        b = _gcry_private_malloc_secure(n);
176      else
177        b = _gcry_private_malloc(n);
178      if (!b)
179        return NULL;
180      memcpy (b, a, len);
181      memset (b+len, 0, n-len);
182      _gcry_private_free (p);
183      return b;
184    }
185  else if ( _gcry_private_is_secure(a) )
186    {
187      return _gcry_secmem_realloc( a, n );
188    }
189  else
190    {
191      return realloc( a, n );
192    }
193}
194
195
196void
197_gcry_private_check_heap (const void *a)
198{
199  if (use_m_guard)
200    {
201      const byte *p = a;
202      size_t len;
203
204      if (!p)
205        return;
206
207      if ( !(p[-1] == MAGIC_NOR_BYTE || p[-1] == MAGIC_SEC_BYTE) )
208        _gcry_log_fatal ("memory at %p corrupted (underflow=%02x)\n", p, p[-1]);
209      len  = p[-4];
210      len |= p[-3] << 8;
211      len |= p[-2] << 16;
212      if ( p[len] != MAGIC_END_BYTE )
213        _gcry_log_fatal ("memory at %p corrupted (overflow=%02x)\n", p, p[-1]);
214    }
215}
216
217
218/*
219 * Free a memory block allocated by this or the secmem module
220 */
221void
222_gcry_private_free (void *a)
223{
224  unsigned char *p = a;
225
226  if (!p)
227    return;
228  if (use_m_guard )
229    {
230      _gcry_private_check_heap(p);
231      if ( _gcry_private_is_secure(a) )
232        _gcry_secmem_free(p-EXTRA_ALIGN-4);
233      else
234        {
235          free(p-EXTRA_ALIGN-4);
236	}
237    }
238  else if ( _gcry_private_is_secure(a) )
239    _gcry_secmem_free(p);
240  else
241    free(p);
242}
243