blob: 38b1050823e95dd02f47ac73405b07c8cbb73d45 [file] [log] [blame]
Paul Bakker6e339b52013-07-03 13:37:05 +02001/*
2 * Buffer-based memory allocator
3 *
Manuel Pégourié-Gonnarda658a402015-01-23 09:45:19 +00004 * Copyright (C) 2006-2014, ARM Limited, All Rights Reserved
Paul Bakker6e339b52013-07-03 13:37:05 +02005 *
Manuel Pégourié-Gonnardfe446432015-03-06 13:17:10 +00006 * This file is part of mbed TLS (https://tls.mbed.org)
Paul Bakker6e339b52013-07-03 13:37:05 +02007 *
Paul Bakker6e339b52013-07-03 13:37:05 +02008 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; if not, write to the Free Software Foundation, Inc.,
20 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 */
22
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020023#if !defined(MBEDTLS_CONFIG_FILE)
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000024#include "mbedtls/config.h"
Manuel Pégourié-Gonnardcef4ad22014-04-29 12:39:06 +020025#else
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020026#include MBEDTLS_CONFIG_FILE
Manuel Pégourié-Gonnardcef4ad22014-04-29 12:39:06 +020027#endif
Paul Bakker6e339b52013-07-03 13:37:05 +020028
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020029#if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C)
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000030#include "mbedtls/memory_buffer_alloc.h"
Paul Bakker6e339b52013-07-03 13:37:05 +020031
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020032/* No need for the header guard as MBEDTLS_MEMORY_BUFFER_ALLOC_C
33 is dependent upon MBEDTLS_PLATFORM_C */
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000034#include "mbedtls/platform.h"
Rich Evansd08a6052015-02-12 12:17:10 +000035
Paul Bakker6e339b52013-07-03 13:37:05 +020036#include <string.h>
37
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020038#if defined(MBEDTLS_MEMORY_BACKTRACE)
Paul Bakker6e339b52013-07-03 13:37:05 +020039#include <execinfo.h>
40#endif
Paul Bakker6e339b52013-07-03 13:37:05 +020041
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020042#if defined(MBEDTLS_THREADING_C)
Manuel Pégourié-Gonnard7f809972015-03-09 17:05:11 +000043#include "mbedtls/threading.h"
Paul Bakker1337aff2013-09-29 14:45:34 +020044#endif
45
Paul Bakker34617722014-06-13 17:20:13 +020046/* Implementation that should never be optimized out by the compiler */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020047static void mbedtls_zeroize( void *v, size_t n ) {
Paul Bakker34617722014-06-13 17:20:13 +020048 volatile unsigned char *p = v; while( n-- ) *p++ = 0;
49}
50
Paul Bakker6e339b52013-07-03 13:37:05 +020051#define MAGIC1 0xFF00AA55
52#define MAGIC2 0xEE119966
53#define MAX_BT 20
54
55typedef struct _memory_header memory_header;
56struct _memory_header
57{
58 size_t magic1;
59 size_t size;
60 size_t alloc;
61 memory_header *prev;
62 memory_header *next;
Paul Bakker1ef120f2013-07-03 17:20:39 +020063 memory_header *prev_free;
64 memory_header *next_free;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020065#if defined(MBEDTLS_MEMORY_BACKTRACE)
Paul Bakker6e339b52013-07-03 13:37:05 +020066 char **trace;
67 size_t trace_count;
68#endif
69 size_t magic2;
70};
71
72typedef struct
73{
74 unsigned char *buf;
75 size_t len;
76 memory_header *first;
Paul Bakker1ef120f2013-07-03 17:20:39 +020077 memory_header *first_free;
Paul Bakker6e339b52013-07-03 13:37:05 +020078 int verify;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020079#if defined(MBEDTLS_MEMORY_DEBUG)
Paul Bakker891998e2013-07-03 14:45:05 +020080 size_t malloc_count;
81 size_t free_count;
82 size_t total_used;
83 size_t maximum_used;
84 size_t header_count;
Manuel Pégourié-Gonnard70896a02013-12-30 18:06:41 +010085 size_t maximum_header_count;
Paul Bakker891998e2013-07-03 14:45:05 +020086#endif
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020087#if defined(MBEDTLS_THREADING_C)
88 mbedtls_threading_mutex_t mutex;
Paul Bakker1337aff2013-09-29 14:45:34 +020089#endif
Paul Bakker6e339b52013-07-03 13:37:05 +020090}
91buffer_alloc_ctx;
92
93static buffer_alloc_ctx heap;
94
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020095#if defined(MBEDTLS_MEMORY_DEBUG)
Paul Bakker6e339b52013-07-03 13:37:05 +020096static void debug_header( memory_header *hdr )
97{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +020098#if defined(MBEDTLS_MEMORY_BACKTRACE)
Paul Bakker6e339b52013-07-03 13:37:05 +020099 size_t i;
100#endif
101
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200102 mbedtls_fprintf( stderr, "HDR: PTR(%10zu), PREV(%10zu), NEXT(%10zu), "
Manuel Pégourié-Gonnard97884a32014-07-12 02:27:35 +0200103 "ALLOC(%zu), SIZE(%10zu)\n",
Paul Bakker7dc4c442014-02-01 22:50:26 +0100104 (size_t) hdr, (size_t) hdr->prev, (size_t) hdr->next,
105 hdr->alloc, hdr->size );
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200106 mbedtls_fprintf( stderr, " FPREV(%10zu), FNEXT(%10zu)\n",
Paul Bakker7dc4c442014-02-01 22:50:26 +0100107 (size_t) hdr->prev_free, (size_t) hdr->next_free );
Paul Bakker6e339b52013-07-03 13:37:05 +0200108
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200109#if defined(MBEDTLS_MEMORY_BACKTRACE)
110 mbedtls_fprintf( stderr, "TRACE: \n" );
Paul Bakker6e339b52013-07-03 13:37:05 +0200111 for( i = 0; i < hdr->trace_count; i++ )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200112 mbedtls_fprintf( stderr, "%s\n", hdr->trace[i] );
113 mbedtls_fprintf( stderr, "\n" );
Paul Bakker6e339b52013-07-03 13:37:05 +0200114#endif
115}
116
117static void debug_chain()
118{
119 memory_header *cur = heap.first;
120
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200121 mbedtls_fprintf( stderr, "\nBlock list\n" );
Paul Bakker6e339b52013-07-03 13:37:05 +0200122 while( cur != NULL )
123 {
124 debug_header( cur );
Paul Bakker6e339b52013-07-03 13:37:05 +0200125 cur = cur->next;
126 }
Paul Bakker1ef120f2013-07-03 17:20:39 +0200127
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200128 mbedtls_fprintf( stderr, "Free list\n" );
Paul Bakker1ef120f2013-07-03 17:20:39 +0200129 cur = heap.first_free;
130
131 while( cur != NULL )
132 {
133 debug_header( cur );
134 cur = cur->next_free;
135 }
Paul Bakker6e339b52013-07-03 13:37:05 +0200136}
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200137#endif /* MBEDTLS_MEMORY_DEBUG */
Paul Bakker6e339b52013-07-03 13:37:05 +0200138
139static int verify_header( memory_header *hdr )
140{
141 if( hdr->magic1 != MAGIC1 )
142 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200143#if defined(MBEDTLS_MEMORY_DEBUG)
144 mbedtls_fprintf( stderr, "FATAL: MAGIC1 mismatch\n" );
Paul Bakker6e339b52013-07-03 13:37:05 +0200145#endif
146 return( 1 );
147 }
148
149 if( hdr->magic2 != MAGIC2 )
150 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200151#if defined(MBEDTLS_MEMORY_DEBUG)
152 mbedtls_fprintf( stderr, "FATAL: MAGIC2 mismatch\n" );
Paul Bakker6e339b52013-07-03 13:37:05 +0200153#endif
154 return( 1 );
155 }
156
157 if( hdr->alloc > 1 )
158 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200159#if defined(MBEDTLS_MEMORY_DEBUG)
160 mbedtls_fprintf( stderr, "FATAL: alloc has illegal value\n" );
Paul Bakker6e339b52013-07-03 13:37:05 +0200161#endif
162 return( 1 );
163 }
164
Paul Bakker1ef120f2013-07-03 17:20:39 +0200165 if( hdr->prev != NULL && hdr->prev == hdr->next )
166 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200167#if defined(MBEDTLS_MEMORY_DEBUG)
168 mbedtls_fprintf( stderr, "FATAL: prev == next\n" );
Paul Bakker1ef120f2013-07-03 17:20:39 +0200169#endif
170 return( 1 );
171 }
172
173 if( hdr->prev_free != NULL && hdr->prev_free == hdr->next_free )
174 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200175#if defined(MBEDTLS_MEMORY_DEBUG)
176 mbedtls_fprintf( stderr, "FATAL: prev_free == next_free\n" );
Paul Bakker1ef120f2013-07-03 17:20:39 +0200177#endif
178 return( 1 );
179 }
180
Paul Bakker6e339b52013-07-03 13:37:05 +0200181 return( 0 );
182}
183
184static int verify_chain()
185{
186 memory_header *prv = heap.first, *cur = heap.first->next;
187
188 if( verify_header( heap.first ) != 0 )
189 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200190#if defined(MBEDTLS_MEMORY_DEBUG)
191 mbedtls_fprintf( stderr, "FATAL: verification of first header "
Paul Bakker7dc4c442014-02-01 22:50:26 +0100192 "failed\n" );
Paul Bakker6e339b52013-07-03 13:37:05 +0200193#endif
194 return( 1 );
195 }
196
197 if( heap.first->prev != NULL )
198 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200199#if defined(MBEDTLS_MEMORY_DEBUG)
200 mbedtls_fprintf( stderr, "FATAL: verification failed: "
Paul Bakker7dc4c442014-02-01 22:50:26 +0100201 "first->prev != NULL\n" );
Paul Bakker6e339b52013-07-03 13:37:05 +0200202#endif
203 return( 1 );
204 }
205
206 while( cur != NULL )
207 {
208 if( verify_header( cur ) != 0 )
209 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200210#if defined(MBEDTLS_MEMORY_DEBUG)
211 mbedtls_fprintf( stderr, "FATAL: verification of header "
Paul Bakker7dc4c442014-02-01 22:50:26 +0100212 "failed\n" );
Paul Bakker6e339b52013-07-03 13:37:05 +0200213#endif
214 return( 1 );
215 }
216
217 if( cur->prev != prv )
218 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200219#if defined(MBEDTLS_MEMORY_DEBUG)
220 mbedtls_fprintf( stderr, "FATAL: verification failed: "
Paul Bakker7dc4c442014-02-01 22:50:26 +0100221 "cur->prev != prv\n" );
Paul Bakker6e339b52013-07-03 13:37:05 +0200222#endif
223 return( 1 );
224 }
225
226 prv = cur;
227 cur = cur->next;
228 }
229
230 return( 0 );
231}
232
233static void *buffer_alloc_malloc( size_t len )
234{
Paul Bakker1ef120f2013-07-03 17:20:39 +0200235 memory_header *new, *cur = heap.first_free;
Paul Bakker6e339b52013-07-03 13:37:05 +0200236 unsigned char *p;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200237#if defined(MBEDTLS_MEMORY_BACKTRACE)
Paul Bakker6e339b52013-07-03 13:37:05 +0200238 void *trace_buffer[MAX_BT];
239 size_t trace_cnt;
240#endif
241
242 if( heap.buf == NULL || heap.first == NULL )
243 return( NULL );
244
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200245 if( len % MBEDTLS_MEMORY_ALIGN_MULTIPLE )
Paul Bakker6e339b52013-07-03 13:37:05 +0200246 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200247 len -= len % MBEDTLS_MEMORY_ALIGN_MULTIPLE;
248 len += MBEDTLS_MEMORY_ALIGN_MULTIPLE;
Paul Bakker6e339b52013-07-03 13:37:05 +0200249 }
250
251 // Find block that fits
252 //
253 while( cur != NULL )
254 {
Paul Bakker1ef120f2013-07-03 17:20:39 +0200255 if( cur->size >= len )
Paul Bakker6e339b52013-07-03 13:37:05 +0200256 break;
257
Paul Bakker1ef120f2013-07-03 17:20:39 +0200258 cur = cur->next_free;
Paul Bakker6e339b52013-07-03 13:37:05 +0200259 }
260
261 if( cur == NULL )
262 return( NULL );
263
Paul Bakker1ef120f2013-07-03 17:20:39 +0200264 if( cur->alloc != 0 )
265 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200266#if defined(MBEDTLS_MEMORY_DEBUG)
267 mbedtls_fprintf( stderr, "FATAL: block in free_list but allocated "
Paul Bakker7dc4c442014-02-01 22:50:26 +0100268 "data\n" );
Paul Bakker1ef120f2013-07-03 17:20:39 +0200269#endif
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200270 mbedtls_exit( 1 );
Paul Bakker1ef120f2013-07-03 17:20:39 +0200271 }
272
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200273#if defined(MBEDTLS_MEMORY_DEBUG)
Paul Bakker891998e2013-07-03 14:45:05 +0200274 heap.malloc_count++;
275#endif
276
Paul Bakker6e339b52013-07-03 13:37:05 +0200277 // Found location, split block if > memory_header + 4 room left
278 //
Paul Bakkerb9e4e2c2014-05-01 14:18:25 +0200279 if( cur->size - len < sizeof(memory_header) +
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200280 MBEDTLS_MEMORY_ALIGN_MULTIPLE )
Paul Bakker6e339b52013-07-03 13:37:05 +0200281 {
282 cur->alloc = 1;
283
Paul Bakker1ef120f2013-07-03 17:20:39 +0200284 // Remove from free_list
285 //
286 if( cur->prev_free != NULL )
287 cur->prev_free->next_free = cur->next_free;
288 else
289 heap.first_free = cur->next_free;
290
291 if( cur->next_free != NULL )
292 cur->next_free->prev_free = cur->prev_free;
293
294 cur->prev_free = NULL;
295 cur->next_free = NULL;
296
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200297#if defined(MBEDTLS_MEMORY_DEBUG)
Paul Bakker891998e2013-07-03 14:45:05 +0200298 heap.total_used += cur->size;
Paul Bakker66d5d072014-06-17 16:39:18 +0200299 if( heap.total_used > heap.maximum_used )
Paul Bakker891998e2013-07-03 14:45:05 +0200300 heap.maximum_used = heap.total_used;
301#endif
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200302#if defined(MBEDTLS_MEMORY_BACKTRACE)
Paul Bakker6e339b52013-07-03 13:37:05 +0200303 trace_cnt = backtrace( trace_buffer, MAX_BT );
304 cur->trace = backtrace_symbols( trace_buffer, trace_cnt );
305 cur->trace_count = trace_cnt;
306#endif
307
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200308 if( ( heap.verify & MBEDTLS_MEMORY_VERIFY_ALLOC ) && verify_chain() != 0 )
309 mbedtls_exit( 1 );
Paul Bakker6e339b52013-07-03 13:37:05 +0200310
Paul Bakkerd8bb8262014-06-17 14:06:49 +0200311 return( ( (unsigned char *) cur ) + sizeof(memory_header) );
Paul Bakker6e339b52013-07-03 13:37:05 +0200312 }
313
314 p = ( (unsigned char *) cur ) + sizeof(memory_header) + len;
315 new = (memory_header *) p;
316
317 new->size = cur->size - len - sizeof(memory_header);
318 new->alloc = 0;
319 new->prev = cur;
320 new->next = cur->next;
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200321#if defined(MBEDTLS_MEMORY_BACKTRACE)
Paul Bakker6e339b52013-07-03 13:37:05 +0200322 new->trace = NULL;
323 new->trace_count = 0;
324#endif
325 new->magic1 = MAGIC1;
326 new->magic2 = MAGIC2;
327
328 if( new->next != NULL )
329 new->next->prev = new;
330
Paul Bakker1ef120f2013-07-03 17:20:39 +0200331 // Replace cur with new in free_list
332 //
333 new->prev_free = cur->prev_free;
334 new->next_free = cur->next_free;
335 if( new->prev_free != NULL )
336 new->prev_free->next_free = new;
337 else
338 heap.first_free = new;
339
340 if( new->next_free != NULL )
341 new->next_free->prev_free = new;
342
Paul Bakker6e339b52013-07-03 13:37:05 +0200343 cur->alloc = 1;
344 cur->size = len;
345 cur->next = new;
Paul Bakker1ef120f2013-07-03 17:20:39 +0200346 cur->prev_free = NULL;
347 cur->next_free = NULL;
Paul Bakker6e339b52013-07-03 13:37:05 +0200348
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200349#if defined(MBEDTLS_MEMORY_DEBUG)
Paul Bakker891998e2013-07-03 14:45:05 +0200350 heap.header_count++;
Manuel Pégourié-Gonnard70896a02013-12-30 18:06:41 +0100351 if( heap.header_count > heap.maximum_header_count )
352 heap.maximum_header_count = heap.header_count;
Paul Bakker891998e2013-07-03 14:45:05 +0200353 heap.total_used += cur->size;
Paul Bakker66d5d072014-06-17 16:39:18 +0200354 if( heap.total_used > heap.maximum_used )
Paul Bakker891998e2013-07-03 14:45:05 +0200355 heap.maximum_used = heap.total_used;
356#endif
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200357#if defined(MBEDTLS_MEMORY_BACKTRACE)
Paul Bakker6e339b52013-07-03 13:37:05 +0200358 trace_cnt = backtrace( trace_buffer, MAX_BT );
359 cur->trace = backtrace_symbols( trace_buffer, trace_cnt );
360 cur->trace_count = trace_cnt;
361#endif
362
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200363 if( ( heap.verify & MBEDTLS_MEMORY_VERIFY_ALLOC ) && verify_chain() != 0 )
364 mbedtls_exit( 1 );
Paul Bakker6e339b52013-07-03 13:37:05 +0200365
Paul Bakkerd8bb8262014-06-17 14:06:49 +0200366 return( ( (unsigned char *) cur ) + sizeof(memory_header) );
Paul Bakker6e339b52013-07-03 13:37:05 +0200367}
368
369static void buffer_alloc_free( void *ptr )
370{
Paul Bakker1ef120f2013-07-03 17:20:39 +0200371 memory_header *hdr, *old = NULL;
Paul Bakker6e339b52013-07-03 13:37:05 +0200372 unsigned char *p = (unsigned char *) ptr;
373
Paul Bakker6e339b52013-07-03 13:37:05 +0200374 if( ptr == NULL || heap.buf == NULL || heap.first == NULL )
375 return;
376
377 if( p < heap.buf || p > heap.buf + heap.len )
378 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200379#if defined(MBEDTLS_MEMORY_DEBUG)
380 mbedtls_fprintf( stderr, "FATAL: mbedtls_free() outside of managed "
Paul Bakker7dc4c442014-02-01 22:50:26 +0100381 "space\n" );
Paul Bakker6e339b52013-07-03 13:37:05 +0200382#endif
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200383 mbedtls_exit( 1 );
Paul Bakker6e339b52013-07-03 13:37:05 +0200384 }
385
386 p -= sizeof(memory_header);
387 hdr = (memory_header *) p;
388
389 if( verify_header( hdr ) != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200390 mbedtls_exit( 1 );
Paul Bakker6e339b52013-07-03 13:37:05 +0200391
392 if( hdr->alloc != 1 )
393 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200394#if defined(MBEDTLS_MEMORY_DEBUG)
395 mbedtls_fprintf( stderr, "FATAL: mbedtls_free() on unallocated "
Paul Bakker7dc4c442014-02-01 22:50:26 +0100396 "data\n" );
Paul Bakker6e339b52013-07-03 13:37:05 +0200397#endif
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200398 mbedtls_exit( 1 );
Paul Bakker6e339b52013-07-03 13:37:05 +0200399 }
400
401 hdr->alloc = 0;
402
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200403#if defined(MBEDTLS_MEMORY_DEBUG)
Paul Bakker891998e2013-07-03 14:45:05 +0200404 heap.free_count++;
405 heap.total_used -= hdr->size;
406#endif
407
Paul Bakker6e339b52013-07-03 13:37:05 +0200408 // Regroup with block before
409 //
410 if( hdr->prev != NULL && hdr->prev->alloc == 0 )
411 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200412#if defined(MBEDTLS_MEMORY_DEBUG)
Paul Bakker891998e2013-07-03 14:45:05 +0200413 heap.header_count--;
414#endif
Paul Bakker6e339b52013-07-03 13:37:05 +0200415 hdr->prev->size += sizeof(memory_header) + hdr->size;
416 hdr->prev->next = hdr->next;
417 old = hdr;
418 hdr = hdr->prev;
419
420 if( hdr->next != NULL )
421 hdr->next->prev = hdr;
422
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200423#if defined(MBEDTLS_MEMORY_BACKTRACE)
Paul Bakker6e339b52013-07-03 13:37:05 +0200424 free( old->trace );
425#endif
426 memset( old, 0, sizeof(memory_header) );
427 }
428
429 // Regroup with block after
430 //
431 if( hdr->next != NULL && hdr->next->alloc == 0 )
432 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200433#if defined(MBEDTLS_MEMORY_DEBUG)
Paul Bakker891998e2013-07-03 14:45:05 +0200434 heap.header_count--;
435#endif
Paul Bakker6e339b52013-07-03 13:37:05 +0200436 hdr->size += sizeof(memory_header) + hdr->next->size;
437 old = hdr->next;
438 hdr->next = hdr->next->next;
439
Paul Bakker1ef120f2013-07-03 17:20:39 +0200440 if( hdr->prev_free != NULL || hdr->next_free != NULL )
441 {
442 if( hdr->prev_free != NULL )
443 hdr->prev_free->next_free = hdr->next_free;
444 else
445 heap.first_free = hdr->next_free;
446
447 if( hdr->next_free != NULL )
448 hdr->next_free->prev_free = hdr->prev_free;
449 }
450
451 hdr->prev_free = old->prev_free;
452 hdr->next_free = old->next_free;
453
454 if( hdr->prev_free != NULL )
455 hdr->prev_free->next_free = hdr;
456 else
457 heap.first_free = hdr;
458
459 if( hdr->next_free != NULL )
460 hdr->next_free->prev_free = hdr;
461
Paul Bakker6e339b52013-07-03 13:37:05 +0200462 if( hdr->next != NULL )
463 hdr->next->prev = hdr;
464
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200465#if defined(MBEDTLS_MEMORY_BACKTRACE)
Paul Bakker6e339b52013-07-03 13:37:05 +0200466 free( old->trace );
467#endif
468 memset( old, 0, sizeof(memory_header) );
469 }
470
Paul Bakker1ef120f2013-07-03 17:20:39 +0200471 // Prepend to free_list if we have not merged
472 // (Does not have to stay in same order as prev / next list)
473 //
474 if( old == NULL )
475 {
476 hdr->next_free = heap.first_free;
Manuel Pégourié-Gonnard547ff662014-11-26 15:42:16 +0100477 if( heap.first_free != NULL )
478 heap.first_free->prev_free = hdr;
Paul Bakker1ef120f2013-07-03 17:20:39 +0200479 heap.first_free = hdr;
480 }
481
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200482#if defined(MBEDTLS_MEMORY_BACKTRACE)
Paul Bakker6e339b52013-07-03 13:37:05 +0200483 hdr->trace = NULL;
484 hdr->trace_count = 0;
485#endif
486
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200487 if( ( heap.verify & MBEDTLS_MEMORY_VERIFY_FREE ) && verify_chain() != 0 )
488 mbedtls_exit( 1 );
Paul Bakker6e339b52013-07-03 13:37:05 +0200489}
490
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200491void mbedtls_memory_buffer_set_verify( int verify )
Paul Bakkerbf796ac2013-09-28 11:06:38 +0200492{
493 heap.verify = verify;
494}
495
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200496int mbedtls_memory_buffer_alloc_verify()
Paul Bakker6e339b52013-07-03 13:37:05 +0200497{
498 return verify_chain();
499}
500
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200501#if defined(MBEDTLS_MEMORY_DEBUG)
502void mbedtls_memory_buffer_alloc_status()
Paul Bakker6e339b52013-07-03 13:37:05 +0200503{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200504 mbedtls_fprintf( stderr,
Manuel Pégourié-Gonnard97884a32014-07-12 02:27:35 +0200505 "Current use: %zu blocks / %zu bytes, max: %zu blocks / "
506 "%zu bytes (total %zu bytes), malloc / free: %zu / %zu\n",
Paul Bakker7dc4c442014-02-01 22:50:26 +0100507 heap.header_count, heap.total_used,
508 heap.maximum_header_count, heap.maximum_used,
509 heap.maximum_header_count * sizeof( memory_header )
510 + heap.maximum_used,
511 heap.malloc_count, heap.free_count );
Paul Bakker891998e2013-07-03 14:45:05 +0200512
Paul Bakker6e339b52013-07-03 13:37:05 +0200513 if( heap.first->next == NULL )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200514 mbedtls_fprintf( stderr, "All memory de-allocated in stack buffer\n" );
Paul Bakker6e339b52013-07-03 13:37:05 +0200515 else
516 {
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200517 mbedtls_fprintf( stderr, "Memory currently allocated:\n" );
Paul Bakker6e339b52013-07-03 13:37:05 +0200518 debug_chain();
519 }
520}
Manuel Pégourié-Gonnard50da0482014-12-19 12:10:37 +0100521
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200522void mbedtls_memory_buffer_alloc_max_get( size_t *max_used, size_t *max_blocks )
Manuel Pégourié-Gonnard50da0482014-12-19 12:10:37 +0100523{
524 *max_used = heap.maximum_used;
525 *max_blocks = heap.maximum_header_count;
526}
527
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200528void mbedtls_memory_buffer_alloc_max_reset( void )
Manuel Pégourié-Gonnard50da0482014-12-19 12:10:37 +0100529{
530 heap.maximum_used = 0;
531 heap.maximum_header_count = 0;
532}
533
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200534void mbedtls_memory_buffer_alloc_cur_get( size_t *cur_used, size_t *cur_blocks )
Manuel Pégourié-Gonnard50da0482014-12-19 12:10:37 +0100535{
536 *cur_used = heap.total_used;
537 *cur_blocks = heap.header_count;
538}
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200539#endif /* MBEDTLS_MEMORY_DEBUG */
Paul Bakker6e339b52013-07-03 13:37:05 +0200540
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200541#if defined(MBEDTLS_THREADING_C)
Paul Bakker1337aff2013-09-29 14:45:34 +0200542static void *buffer_alloc_malloc_mutexed( size_t len )
543{
544 void *buf;
Manuel Pégourié-Gonnardbdd78282015-04-24 14:42:53 +0200545 if( mbedtls_mutex_lock( &heap.mutex ) != 0 )
546 return( NULL );
Paul Bakker1337aff2013-09-29 14:45:34 +0200547 buf = buffer_alloc_malloc( len );
Manuel Pégourié-Gonnardbdd78282015-04-24 14:42:53 +0200548 if( mbedtls_mutex_unlock( &heap.mutex ) )
549 return( NULL );
Paul Bakker1337aff2013-09-29 14:45:34 +0200550 return( buf );
551}
552
553static void buffer_alloc_free_mutexed( void *ptr )
554{
Manuel Pégourié-Gonnardbdd78282015-04-24 14:42:53 +0200555 /* We have to good option here, but corrupting the heap seems
556 * worse than loosing memory. */
557 if( mbedtls_mutex_lock( &heap.mutex ) )
558 return;
Paul Bakker1337aff2013-09-29 14:45:34 +0200559 buffer_alloc_free( ptr );
Manuel Pégourié-Gonnardbdd78282015-04-24 14:42:53 +0200560 (void) mbedtls_mutex_unlock( &heap.mutex );
Paul Bakker1337aff2013-09-29 14:45:34 +0200561}
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200562#endif /* MBEDTLS_THREADING_C */
Paul Bakker1337aff2013-09-29 14:45:34 +0200563
Manuel Pégourié-Gonnard69a69cc2015-04-29 01:05:19 +0200564void mbedtls_memory_buffer_alloc_init( unsigned char *buf, size_t len )
Paul Bakker6e339b52013-07-03 13:37:05 +0200565{
Paul Bakker6e339b52013-07-03 13:37:05 +0200566 memset( &heap, 0, sizeof(buffer_alloc_ctx) );
567 memset( buf, 0, len );
568
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200569#if defined(MBEDTLS_THREADING_C)
570 mbedtls_mutex_init( &heap.mutex );
571 mbedtls_platform_set_malloc_free( buffer_alloc_malloc_mutexed,
Paul Bakkerdefc0ca2014-02-04 17:30:24 +0100572 buffer_alloc_free_mutexed );
Paul Bakker1337aff2013-09-29 14:45:34 +0200573#else
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200574 mbedtls_platform_set_malloc_free( buffer_alloc_malloc, buffer_alloc_free );
Paul Bakker1337aff2013-09-29 14:45:34 +0200575#endif
576
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200577 if( (size_t) buf % MBEDTLS_MEMORY_ALIGN_MULTIPLE )
Manuel Pégourié-Gonnard82a5de72014-05-05 14:05:24 +0200578 {
Manuel Pégourié-Gonnard5dd28ea2014-11-27 13:57:42 +0100579 /* Adjust len first since buf is used in the computation */
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200580 len -= MBEDTLS_MEMORY_ALIGN_MULTIPLE
581 - (size_t) buf % MBEDTLS_MEMORY_ALIGN_MULTIPLE;
582 buf += MBEDTLS_MEMORY_ALIGN_MULTIPLE
583 - (size_t) buf % MBEDTLS_MEMORY_ALIGN_MULTIPLE;
Manuel Pégourié-Gonnard82a5de72014-05-05 14:05:24 +0200584 }
585
Paul Bakker6e339b52013-07-03 13:37:05 +0200586 heap.buf = buf;
587 heap.len = len;
588
589 heap.first = (memory_header *) buf;
590 heap.first->size = len - sizeof(memory_header);
591 heap.first->magic1 = MAGIC1;
592 heap.first->magic2 = MAGIC2;
Paul Bakker1ef120f2013-07-03 17:20:39 +0200593 heap.first_free = heap.first;
Paul Bakker6e339b52013-07-03 13:37:05 +0200594}
595
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200596void mbedtls_memory_buffer_alloc_free()
Paul Bakker1337aff2013-09-29 14:45:34 +0200597{
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200598#if defined(MBEDTLS_THREADING_C)
599 mbedtls_mutex_free( &heap.mutex );
Paul Bakker1337aff2013-09-29 14:45:34 +0200600#endif
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200601 mbedtls_zeroize( &heap, sizeof(buffer_alloc_ctx) );
Paul Bakker1337aff2013-09-29 14:45:34 +0200602}
603
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200604#if defined(MBEDTLS_SELF_TEST)
Manuel Pégourié-Gonnard5ba1d522014-11-27 11:33:55 +0100605static int check_pointer( void *p )
606{
607 if( p == NULL )
608 return( -1 );
609
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200610 if( (size_t) p % MBEDTLS_MEMORY_ALIGN_MULTIPLE != 0 )
Manuel Pégourié-Gonnard5ba1d522014-11-27 11:33:55 +0100611 return( -1 );
612
613 return( 0 );
614}
615
616static int check_all_free( )
617{
Manuel Pégourié-Gonnard491a3fe2015-02-05 12:08:47 +0100618 if(
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200619#if defined(MBEDTLS_MEMORY_DEBUG)
Manuel Pégourié-Gonnard491a3fe2015-02-05 12:08:47 +0100620 heap.total_used != 0 ||
621#endif
Manuel Pégourié-Gonnard5ba1d522014-11-27 11:33:55 +0100622 heap.first != heap.first_free ||
623 (void *) heap.first != (void *) heap.buf )
624 {
625 return( -1 );
626 }
627
628 return( 0 );
629}
630
631#define TEST_ASSERT( condition ) \
632 if( ! (condition) ) \
633 { \
634 if( verbose != 0 ) \
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200635 mbedtls_printf( "failed\n" ); \
Manuel Pégourié-Gonnard5ba1d522014-11-27 11:33:55 +0100636 \
637 ret = 1; \
638 goto cleanup; \
639 }
640
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200641int mbedtls_memory_buffer_alloc_self_test( int verbose )
Manuel Pégourié-Gonnard5ba1d522014-11-27 11:33:55 +0100642{
Manuel Pégourié-Gonnard5ba1d522014-11-27 11:33:55 +0100643 unsigned char buf[1024];
Manuel Pégourié-Gonnard5dd28ea2014-11-27 13:57:42 +0100644 unsigned char *p, *q, *r, *end;
645 int ret = 0;
Manuel Pégourié-Gonnard5ba1d522014-11-27 11:33:55 +0100646
647 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200648 mbedtls_printf( " MBA test #1 (basic alloc-free cycle): " );
Manuel Pégourié-Gonnard5ba1d522014-11-27 11:33:55 +0100649
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200650 mbedtls_memory_buffer_alloc_init( buf, sizeof( buf ) );
Manuel Pégourié-Gonnard5ba1d522014-11-27 11:33:55 +0100651
Manuel Pégourié-Gonnard7551cb92015-05-26 16:04:06 +0200652 p = mbedtls_calloc( 1, 1 );
653 q = mbedtls_calloc( 1, 128 );
654 r = mbedtls_calloc( 1, 16 );
Manuel Pégourié-Gonnard5ba1d522014-11-27 11:33:55 +0100655
656 TEST_ASSERT( check_pointer( p ) == 0 &&
657 check_pointer( q ) == 0 &&
658 check_pointer( r ) == 0 );
659
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200660 mbedtls_free( r );
661 mbedtls_free( q );
662 mbedtls_free( p );
Manuel Pégourié-Gonnard5ba1d522014-11-27 11:33:55 +0100663
664 TEST_ASSERT( check_all_free( ) == 0 );
665
Manuel Pégourié-Gonnard5dd28ea2014-11-27 13:57:42 +0100666 /* Memorize end to compare with the next test */
667 end = heap.buf + heap.len;
668
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200669 mbedtls_memory_buffer_alloc_free( );
Manuel Pégourié-Gonnard5ba1d522014-11-27 11:33:55 +0100670
671 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200672 mbedtls_printf( "passed\n" );
Manuel Pégourié-Gonnard5ba1d522014-11-27 11:33:55 +0100673
674 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200675 mbedtls_printf( " MBA test #2 (buf not aligned): " );
Manuel Pégourié-Gonnard5ba1d522014-11-27 11:33:55 +0100676
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200677 mbedtls_memory_buffer_alloc_init( buf + 1, sizeof( buf ) - 1 );
Manuel Pégourié-Gonnard5ba1d522014-11-27 11:33:55 +0100678
Manuel Pégourié-Gonnard5dd28ea2014-11-27 13:57:42 +0100679 TEST_ASSERT( heap.buf + heap.len == end );
680
Manuel Pégourié-Gonnard7551cb92015-05-26 16:04:06 +0200681 p = mbedtls_calloc( 1, 1 );
682 q = mbedtls_calloc( 1, 128 );
683 r = mbedtls_calloc( 1, 16 );
Manuel Pégourié-Gonnard5ba1d522014-11-27 11:33:55 +0100684
685 TEST_ASSERT( check_pointer( p ) == 0 &&
686 check_pointer( q ) == 0 &&
687 check_pointer( r ) == 0 );
688
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200689 mbedtls_free( r );
690 mbedtls_free( q );
691 mbedtls_free( p );
Manuel Pégourié-Gonnard5ba1d522014-11-27 11:33:55 +0100692
693 TEST_ASSERT( check_all_free( ) == 0 );
694
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200695 mbedtls_memory_buffer_alloc_free( );
Manuel Pégourié-Gonnard5ba1d522014-11-27 11:33:55 +0100696
697 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200698 mbedtls_printf( "passed\n" );
Manuel Pégourié-Gonnard5ba1d522014-11-27 11:33:55 +0100699
700 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200701 mbedtls_printf( " MBA test #3 (full): " );
Manuel Pégourié-Gonnard5ba1d522014-11-27 11:33:55 +0100702
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200703 mbedtls_memory_buffer_alloc_init( buf, sizeof( buf ) );
Manuel Pégourié-Gonnard5ba1d522014-11-27 11:33:55 +0100704
Manuel Pégourié-Gonnard7551cb92015-05-26 16:04:06 +0200705 p = mbedtls_calloc( 1, sizeof( buf ) - sizeof( memory_header ) );
Manuel Pégourié-Gonnard5ba1d522014-11-27 11:33:55 +0100706
707 TEST_ASSERT( check_pointer( p ) == 0 );
Manuel Pégourié-Gonnard7551cb92015-05-26 16:04:06 +0200708 TEST_ASSERT( mbedtls_calloc( 1, 1 ) == NULL );
Manuel Pégourié-Gonnard5ba1d522014-11-27 11:33:55 +0100709
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200710 mbedtls_free( p );
Manuel Pégourié-Gonnard5ba1d522014-11-27 11:33:55 +0100711
Manuel Pégourié-Gonnard7551cb92015-05-26 16:04:06 +0200712 p = mbedtls_calloc( 1, sizeof( buf ) - 2 * sizeof( memory_header ) - 16 );
713 q = mbedtls_calloc( 1, 16 );
Manuel Pégourié-Gonnard5ba1d522014-11-27 11:33:55 +0100714
715 TEST_ASSERT( check_pointer( p ) == 0 && check_pointer( q ) == 0 );
Manuel Pégourié-Gonnard7551cb92015-05-26 16:04:06 +0200716 TEST_ASSERT( mbedtls_calloc( 1, 1 ) == NULL );
Manuel Pégourié-Gonnard5ba1d522014-11-27 11:33:55 +0100717
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200718 mbedtls_free( q );
Manuel Pégourié-Gonnard5ba1d522014-11-27 11:33:55 +0100719
Manuel Pégourié-Gonnard7551cb92015-05-26 16:04:06 +0200720 TEST_ASSERT( mbedtls_calloc( 1, 17 ) == NULL );
Manuel Pégourié-Gonnard5ba1d522014-11-27 11:33:55 +0100721
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200722 mbedtls_free( p );
Manuel Pégourié-Gonnard5ba1d522014-11-27 11:33:55 +0100723
724 TEST_ASSERT( check_all_free( ) == 0 );
725
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200726 mbedtls_memory_buffer_alloc_free( );
Manuel Pégourié-Gonnard5ba1d522014-11-27 11:33:55 +0100727
728 if( verbose != 0 )
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200729 mbedtls_printf( "passed\n" );
Manuel Pégourié-Gonnard5ba1d522014-11-27 11:33:55 +0100730
731cleanup:
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200732 mbedtls_memory_buffer_alloc_free( );
Manuel Pégourié-Gonnard5ba1d522014-11-27 11:33:55 +0100733
734 return( ret );
735}
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200736#endif /* MBEDTLS_SELF_TEST */
Manuel Pégourié-Gonnard5ba1d522014-11-27 11:33:55 +0100737
Manuel Pégourié-Gonnard2cf5a7c2015-04-08 12:49:31 +0200738#endif /* MBEDTLS_MEMORY_BUFFER_ALLOC_C */