xref: /optee_os/lib/libmbedtls/mbedtls/library/memory_buffer_alloc.c (revision b0563631928755fe864b97785160fb3088e9efdc)
1817466cbSJens Wiklander /*
2817466cbSJens Wiklander  *  Buffer-based memory allocator
3817466cbSJens Wiklander  *
47901324dSJerome Forissier  *  Copyright The Mbed TLS Contributors
5*b0563631STom Van Eyck  *  SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later
6817466cbSJens Wiklander  */
7817466cbSJens Wiklander 
87901324dSJerome Forissier #include "common.h"
9817466cbSJens Wiklander 
10817466cbSJens Wiklander #if defined(MBEDTLS_MEMORY_BUFFER_ALLOC_C)
11817466cbSJens Wiklander #include "mbedtls/memory_buffer_alloc.h"
12817466cbSJens Wiklander 
13817466cbSJens Wiklander /* No need for the header guard as MBEDTLS_MEMORY_BUFFER_ALLOC_C
14817466cbSJens Wiklander    is dependent upon MBEDTLS_PLATFORM_C */
15817466cbSJens Wiklander #include "mbedtls/platform.h"
163d3b0591SJens Wiklander #include "mbedtls/platform_util.h"
17817466cbSJens Wiklander 
18817466cbSJens Wiklander #include <string.h>
19817466cbSJens Wiklander 
20817466cbSJens Wiklander #if defined(MBEDTLS_MEMORY_BACKTRACE)
21817466cbSJens Wiklander #include <execinfo.h>
22817466cbSJens Wiklander #endif
23817466cbSJens Wiklander 
24817466cbSJens Wiklander #if defined(MBEDTLS_THREADING_C)
25817466cbSJens Wiklander #include "mbedtls/threading.h"
26817466cbSJens Wiklander #endif
27817466cbSJens Wiklander 
28817466cbSJens Wiklander #define MAGIC1       0xFF00AA55
29817466cbSJens Wiklander #define MAGIC2       0xEE119966
30817466cbSJens Wiklander #define MAX_BT 20
31817466cbSJens Wiklander 
32817466cbSJens Wiklander typedef struct _memory_header memory_header;
3332b31808SJens Wiklander struct _memory_header {
34817466cbSJens Wiklander     size_t          magic1;
35817466cbSJens Wiklander     size_t          size;
36817466cbSJens Wiklander     size_t          alloc;
37817466cbSJens Wiklander     memory_header   *prev;
38817466cbSJens Wiklander     memory_header   *next;
39817466cbSJens Wiklander     memory_header   *prev_free;
40817466cbSJens Wiklander     memory_header   *next_free;
41817466cbSJens Wiklander #if defined(MBEDTLS_MEMORY_BACKTRACE)
42817466cbSJens Wiklander     char            **trace;
43817466cbSJens Wiklander     size_t          trace_count;
44817466cbSJens Wiklander #endif
45817466cbSJens Wiklander     size_t          magic2;
46817466cbSJens Wiklander };
47817466cbSJens Wiklander 
4832b31808SJens Wiklander typedef struct {
49817466cbSJens Wiklander     unsigned char   *buf;
50817466cbSJens Wiklander     size_t          len;
51817466cbSJens Wiklander     memory_header   *first;
52817466cbSJens Wiklander     memory_header   *first_free;
53817466cbSJens Wiklander     int             verify;
54817466cbSJens Wiklander #if defined(MBEDTLS_MEMORY_DEBUG)
55817466cbSJens Wiklander     size_t          alloc_count;
56817466cbSJens Wiklander     size_t          free_count;
57817466cbSJens Wiklander     size_t          total_used;
58817466cbSJens Wiklander     size_t          maximum_used;
59817466cbSJens Wiklander     size_t          header_count;
60817466cbSJens Wiklander     size_t          maximum_header_count;
61817466cbSJens Wiklander #endif
62817466cbSJens Wiklander #if defined(MBEDTLS_THREADING_C)
63817466cbSJens Wiklander     mbedtls_threading_mutex_t   mutex;
64817466cbSJens Wiklander #endif
65817466cbSJens Wiklander }
66817466cbSJens Wiklander buffer_alloc_ctx;
67817466cbSJens Wiklander 
68817466cbSJens Wiklander static buffer_alloc_ctx heap;
69817466cbSJens Wiklander 
70817466cbSJens Wiklander #if defined(MBEDTLS_MEMORY_DEBUG)
debug_header(memory_header * hdr)71817466cbSJens Wiklander static void debug_header(memory_header *hdr)
72817466cbSJens Wiklander {
73817466cbSJens Wiklander #if defined(MBEDTLS_MEMORY_BACKTRACE)
74817466cbSJens Wiklander     size_t i;
75817466cbSJens Wiklander #endif
76817466cbSJens Wiklander 
77817466cbSJens Wiklander     mbedtls_fprintf(stderr, "HDR:  PTR(%10zu), PREV(%10zu), NEXT(%10zu), "
78817466cbSJens Wiklander                             "ALLOC(%zu), SIZE(%10zu)\n",
79817466cbSJens Wiklander                     (size_t) hdr, (size_t) hdr->prev, (size_t) hdr->next,
80817466cbSJens Wiklander                     hdr->alloc, hdr->size);
81817466cbSJens Wiklander     mbedtls_fprintf(stderr, "      FPREV(%10zu), FNEXT(%10zu)\n",
82817466cbSJens Wiklander                     (size_t) hdr->prev_free, (size_t) hdr->next_free);
83817466cbSJens Wiklander 
84817466cbSJens Wiklander #if defined(MBEDTLS_MEMORY_BACKTRACE)
85817466cbSJens Wiklander     mbedtls_fprintf(stderr, "TRACE: \n");
8632b31808SJens Wiklander     for (i = 0; i < hdr->trace_count; i++) {
87817466cbSJens Wiklander         mbedtls_fprintf(stderr, "%s\n", hdr->trace[i]);
8832b31808SJens Wiklander     }
89817466cbSJens Wiklander     mbedtls_fprintf(stderr, "\n");
90817466cbSJens Wiklander #endif
91817466cbSJens Wiklander }
92817466cbSJens Wiklander 
debug_chain(void)933d3b0591SJens Wiklander static void debug_chain(void)
94817466cbSJens Wiklander {
95817466cbSJens Wiklander     memory_header *cur = heap.first;
96817466cbSJens Wiklander 
97817466cbSJens Wiklander     mbedtls_fprintf(stderr, "\nBlock list\n");
9832b31808SJens Wiklander     while (cur != NULL) {
99817466cbSJens Wiklander         debug_header(cur);
100817466cbSJens Wiklander         cur = cur->next;
101817466cbSJens Wiklander     }
102817466cbSJens Wiklander 
103817466cbSJens Wiklander     mbedtls_fprintf(stderr, "Free list\n");
104817466cbSJens Wiklander     cur = heap.first_free;
105817466cbSJens Wiklander 
10632b31808SJens Wiklander     while (cur != NULL) {
107817466cbSJens Wiklander         debug_header(cur);
108817466cbSJens Wiklander         cur = cur->next_free;
109817466cbSJens Wiklander     }
110817466cbSJens Wiklander }
111817466cbSJens Wiklander #endif /* MBEDTLS_MEMORY_DEBUG */
112817466cbSJens Wiklander 
verify_header(memory_header * hdr)113817466cbSJens Wiklander static int verify_header(memory_header *hdr)
114817466cbSJens Wiklander {
11532b31808SJens Wiklander     if (hdr->magic1 != MAGIC1) {
116817466cbSJens Wiklander #if defined(MBEDTLS_MEMORY_DEBUG)
117817466cbSJens Wiklander         mbedtls_fprintf(stderr, "FATAL: MAGIC1 mismatch\n");
118817466cbSJens Wiklander #endif
11932b31808SJens Wiklander         return 1;
120817466cbSJens Wiklander     }
121817466cbSJens Wiklander 
12232b31808SJens Wiklander     if (hdr->magic2 != MAGIC2) {
123817466cbSJens Wiklander #if defined(MBEDTLS_MEMORY_DEBUG)
124817466cbSJens Wiklander         mbedtls_fprintf(stderr, "FATAL: MAGIC2 mismatch\n");
125817466cbSJens Wiklander #endif
12632b31808SJens Wiklander         return 1;
127817466cbSJens Wiklander     }
128817466cbSJens Wiklander 
12932b31808SJens Wiklander     if (hdr->alloc > 1) {
130817466cbSJens Wiklander #if defined(MBEDTLS_MEMORY_DEBUG)
131817466cbSJens Wiklander         mbedtls_fprintf(stderr, "FATAL: alloc has illegal value\n");
132817466cbSJens Wiklander #endif
13332b31808SJens Wiklander         return 1;
134817466cbSJens Wiklander     }
135817466cbSJens Wiklander 
13632b31808SJens Wiklander     if (hdr->prev != NULL && hdr->prev == hdr->next) {
137817466cbSJens Wiklander #if defined(MBEDTLS_MEMORY_DEBUG)
138817466cbSJens Wiklander         mbedtls_fprintf(stderr, "FATAL: prev == next\n");
139817466cbSJens Wiklander #endif
14032b31808SJens Wiklander         return 1;
141817466cbSJens Wiklander     }
142817466cbSJens Wiklander 
14332b31808SJens Wiklander     if (hdr->prev_free != NULL && hdr->prev_free == hdr->next_free) {
144817466cbSJens Wiklander #if defined(MBEDTLS_MEMORY_DEBUG)
145817466cbSJens Wiklander         mbedtls_fprintf(stderr, "FATAL: prev_free == next_free\n");
146817466cbSJens Wiklander #endif
14732b31808SJens Wiklander         return 1;
148817466cbSJens Wiklander     }
149817466cbSJens Wiklander 
15032b31808SJens Wiklander     return 0;
151817466cbSJens Wiklander }
152817466cbSJens Wiklander 
verify_chain(void)1533d3b0591SJens Wiklander static int verify_chain(void)
154817466cbSJens Wiklander {
1553d3b0591SJens Wiklander     memory_header *prv = heap.first, *cur;
156817466cbSJens Wiklander 
15732b31808SJens Wiklander     if (prv == NULL || verify_header(prv) != 0) {
158817466cbSJens Wiklander #if defined(MBEDTLS_MEMORY_DEBUG)
159817466cbSJens Wiklander         mbedtls_fprintf(stderr, "FATAL: verification of first header "
160817466cbSJens Wiklander                                 "failed\n");
161817466cbSJens Wiklander #endif
16232b31808SJens Wiklander         return 1;
163817466cbSJens Wiklander     }
164817466cbSJens Wiklander 
16532b31808SJens Wiklander     if (heap.first->prev != NULL) {
166817466cbSJens Wiklander #if defined(MBEDTLS_MEMORY_DEBUG)
167817466cbSJens Wiklander         mbedtls_fprintf(stderr, "FATAL: verification failed: "
168817466cbSJens Wiklander                                 "first->prev != NULL\n");
169817466cbSJens Wiklander #endif
17032b31808SJens Wiklander         return 1;
171817466cbSJens Wiklander     }
172817466cbSJens Wiklander 
1733d3b0591SJens Wiklander     cur = heap.first->next;
1743d3b0591SJens Wiklander 
17532b31808SJens Wiklander     while (cur != NULL) {
17632b31808SJens Wiklander         if (verify_header(cur) != 0) {
177817466cbSJens Wiklander #if defined(MBEDTLS_MEMORY_DEBUG)
178817466cbSJens Wiklander             mbedtls_fprintf(stderr, "FATAL: verification of header "
179817466cbSJens Wiklander                                     "failed\n");
180817466cbSJens Wiklander #endif
18132b31808SJens Wiklander             return 1;
182817466cbSJens Wiklander         }
183817466cbSJens Wiklander 
18432b31808SJens Wiklander         if (cur->prev != prv) {
185817466cbSJens Wiklander #if defined(MBEDTLS_MEMORY_DEBUG)
186817466cbSJens Wiklander             mbedtls_fprintf(stderr, "FATAL: verification failed: "
187817466cbSJens Wiklander                                     "cur->prev != prv\n");
188817466cbSJens Wiklander #endif
18932b31808SJens Wiklander             return 1;
190817466cbSJens Wiklander         }
191817466cbSJens Wiklander 
192817466cbSJens Wiklander         prv = cur;
193817466cbSJens Wiklander         cur = cur->next;
194817466cbSJens Wiklander     }
195817466cbSJens Wiklander 
19632b31808SJens Wiklander     return 0;
197817466cbSJens Wiklander }
198817466cbSJens Wiklander 
buffer_alloc_calloc(size_t n,size_t size)199817466cbSJens Wiklander static void *buffer_alloc_calloc(size_t n, size_t size)
200817466cbSJens Wiklander {
201817466cbSJens Wiklander     memory_header *new, *cur = heap.first_free;
202817466cbSJens Wiklander     unsigned char *p;
203817466cbSJens Wiklander     void *ret;
204817466cbSJens Wiklander     size_t original_len, len;
205817466cbSJens Wiklander #if defined(MBEDTLS_MEMORY_BACKTRACE)
206817466cbSJens Wiklander     void *trace_buffer[MAX_BT];
207817466cbSJens Wiklander     size_t trace_cnt;
208817466cbSJens Wiklander #endif
209817466cbSJens Wiklander 
21032b31808SJens Wiklander     if (heap.buf == NULL || heap.first == NULL) {
21132b31808SJens Wiklander         return NULL;
21232b31808SJens Wiklander     }
213817466cbSJens Wiklander 
214817466cbSJens Wiklander     original_len = len = n * size;
215817466cbSJens Wiklander 
21632b31808SJens Wiklander     if (n == 0 || size == 0 || len / n != size) {
21732b31808SJens Wiklander         return NULL;
21832b31808SJens Wiklander     } else if (len > (size_t) -MBEDTLS_MEMORY_ALIGN_MULTIPLE) {
21932b31808SJens Wiklander         return NULL;
22032b31808SJens Wiklander     }
221817466cbSJens Wiklander 
22232b31808SJens Wiklander     if (len % MBEDTLS_MEMORY_ALIGN_MULTIPLE) {
223817466cbSJens Wiklander         len -= len % MBEDTLS_MEMORY_ALIGN_MULTIPLE;
224817466cbSJens Wiklander         len += MBEDTLS_MEMORY_ALIGN_MULTIPLE;
225817466cbSJens Wiklander     }
226817466cbSJens Wiklander 
227817466cbSJens Wiklander     // Find block that fits
228817466cbSJens Wiklander     //
22932b31808SJens Wiklander     while (cur != NULL) {
23032b31808SJens Wiklander         if (cur->size >= len) {
231817466cbSJens Wiklander             break;
23232b31808SJens Wiklander         }
233817466cbSJens Wiklander 
234817466cbSJens Wiklander         cur = cur->next_free;
235817466cbSJens Wiklander     }
236817466cbSJens Wiklander 
23732b31808SJens Wiklander     if (cur == NULL) {
23832b31808SJens Wiklander         return NULL;
23932b31808SJens Wiklander     }
240817466cbSJens Wiklander 
24132b31808SJens Wiklander     if (cur->alloc != 0) {
242817466cbSJens Wiklander #if defined(MBEDTLS_MEMORY_DEBUG)
243817466cbSJens Wiklander         mbedtls_fprintf(stderr, "FATAL: block in free_list but allocated "
244817466cbSJens Wiklander                                 "data\n");
245817466cbSJens Wiklander #endif
246817466cbSJens Wiklander         mbedtls_exit(1);
247817466cbSJens Wiklander     }
248817466cbSJens Wiklander 
249817466cbSJens Wiklander #if defined(MBEDTLS_MEMORY_DEBUG)
250817466cbSJens Wiklander     heap.alloc_count++;
251817466cbSJens Wiklander #endif
252817466cbSJens Wiklander 
253817466cbSJens Wiklander     // Found location, split block if > memory_header + 4 room left
254817466cbSJens Wiklander     //
255817466cbSJens Wiklander     if (cur->size - len < sizeof(memory_header) +
25632b31808SJens Wiklander         MBEDTLS_MEMORY_ALIGN_MULTIPLE) {
257817466cbSJens Wiklander         cur->alloc = 1;
258817466cbSJens Wiklander 
259817466cbSJens Wiklander         // Remove from free_list
260817466cbSJens Wiklander         //
26132b31808SJens Wiklander         if (cur->prev_free != NULL) {
262817466cbSJens Wiklander             cur->prev_free->next_free = cur->next_free;
26332b31808SJens Wiklander         } else {
264817466cbSJens Wiklander             heap.first_free = cur->next_free;
26532b31808SJens Wiklander         }
266817466cbSJens Wiklander 
26732b31808SJens Wiklander         if (cur->next_free != NULL) {
268817466cbSJens Wiklander             cur->next_free->prev_free = cur->prev_free;
26932b31808SJens Wiklander         }
270817466cbSJens Wiklander 
271817466cbSJens Wiklander         cur->prev_free = NULL;
272817466cbSJens Wiklander         cur->next_free = NULL;
273817466cbSJens Wiklander 
274817466cbSJens Wiklander #if defined(MBEDTLS_MEMORY_DEBUG)
275817466cbSJens Wiklander         heap.total_used += cur->size;
27632b31808SJens Wiklander         if (heap.total_used > heap.maximum_used) {
277817466cbSJens Wiklander             heap.maximum_used = heap.total_used;
27832b31808SJens Wiklander         }
279817466cbSJens Wiklander #endif
280817466cbSJens Wiklander #if defined(MBEDTLS_MEMORY_BACKTRACE)
281817466cbSJens Wiklander         trace_cnt = backtrace(trace_buffer, MAX_BT);
282817466cbSJens Wiklander         cur->trace = backtrace_symbols(trace_buffer, trace_cnt);
283817466cbSJens Wiklander         cur->trace_count = trace_cnt;
284817466cbSJens Wiklander #endif
285817466cbSJens Wiklander 
28632b31808SJens Wiklander         if ((heap.verify & MBEDTLS_MEMORY_VERIFY_ALLOC) && verify_chain() != 0) {
287817466cbSJens Wiklander             mbedtls_exit(1);
28832b31808SJens Wiklander         }
289817466cbSJens Wiklander 
290817466cbSJens Wiklander         ret = (unsigned char *) cur + sizeof(memory_header);
291817466cbSJens Wiklander         memset(ret, 0, original_len);
292817466cbSJens Wiklander 
29332b31808SJens Wiklander         return ret;
294817466cbSJens Wiklander     }
295817466cbSJens Wiklander 
296817466cbSJens Wiklander     p = ((unsigned char *) cur) + sizeof(memory_header) + len;
297817466cbSJens Wiklander     new = (memory_header *) p;
298817466cbSJens Wiklander 
299817466cbSJens Wiklander     new->size = cur->size - len - sizeof(memory_header);
300817466cbSJens Wiklander     new->alloc = 0;
301817466cbSJens Wiklander     new->prev = cur;
302817466cbSJens Wiklander     new->next = cur->next;
303817466cbSJens Wiklander #if defined(MBEDTLS_MEMORY_BACKTRACE)
304817466cbSJens Wiklander     new->trace = NULL;
305817466cbSJens Wiklander     new->trace_count = 0;
306817466cbSJens Wiklander #endif
307817466cbSJens Wiklander     new->magic1 = MAGIC1;
308817466cbSJens Wiklander     new->magic2 = MAGIC2;
309817466cbSJens Wiklander 
31032b31808SJens Wiklander     if (new->next != NULL) {
311817466cbSJens Wiklander         new->next->prev = new;
31232b31808SJens Wiklander     }
313817466cbSJens Wiklander 
314817466cbSJens Wiklander     // Replace cur with new in free_list
315817466cbSJens Wiklander     //
316817466cbSJens Wiklander     new->prev_free = cur->prev_free;
317817466cbSJens Wiklander     new->next_free = cur->next_free;
31832b31808SJens Wiklander     if (new->prev_free != NULL) {
319817466cbSJens Wiklander         new->prev_free->next_free = new;
32032b31808SJens Wiklander     } else {
321817466cbSJens Wiklander         heap.first_free = new;
32232b31808SJens Wiklander     }
323817466cbSJens Wiklander 
32432b31808SJens Wiklander     if (new->next_free != NULL) {
325817466cbSJens Wiklander         new->next_free->prev_free = new;
32632b31808SJens Wiklander     }
327817466cbSJens Wiklander 
328817466cbSJens Wiklander     cur->alloc = 1;
329817466cbSJens Wiklander     cur->size = len;
330817466cbSJens Wiklander     cur->next = new;
331817466cbSJens Wiklander     cur->prev_free = NULL;
332817466cbSJens Wiklander     cur->next_free = NULL;
333817466cbSJens Wiklander 
334817466cbSJens Wiklander #if defined(MBEDTLS_MEMORY_DEBUG)
335817466cbSJens Wiklander     heap.header_count++;
33632b31808SJens Wiklander     if (heap.header_count > heap.maximum_header_count) {
337817466cbSJens Wiklander         heap.maximum_header_count = heap.header_count;
33832b31808SJens Wiklander     }
339817466cbSJens Wiklander     heap.total_used += cur->size;
34032b31808SJens Wiklander     if (heap.total_used > heap.maximum_used) {
341817466cbSJens Wiklander         heap.maximum_used = heap.total_used;
34232b31808SJens Wiklander     }
343817466cbSJens Wiklander #endif
344817466cbSJens Wiklander #if defined(MBEDTLS_MEMORY_BACKTRACE)
345817466cbSJens Wiklander     trace_cnt = backtrace(trace_buffer, MAX_BT);
346817466cbSJens Wiklander     cur->trace = backtrace_symbols(trace_buffer, trace_cnt);
347817466cbSJens Wiklander     cur->trace_count = trace_cnt;
348817466cbSJens Wiklander #endif
349817466cbSJens Wiklander 
35032b31808SJens Wiklander     if ((heap.verify & MBEDTLS_MEMORY_VERIFY_ALLOC) && verify_chain() != 0) {
351817466cbSJens Wiklander         mbedtls_exit(1);
35232b31808SJens Wiklander     }
353817466cbSJens Wiklander 
354817466cbSJens Wiklander     ret = (unsigned char *) cur + sizeof(memory_header);
355817466cbSJens Wiklander     memset(ret, 0, original_len);
356817466cbSJens Wiklander 
35732b31808SJens Wiklander     return ret;
358817466cbSJens Wiklander }
359817466cbSJens Wiklander 
buffer_alloc_free(void * ptr)360817466cbSJens Wiklander static void buffer_alloc_free(void *ptr)
361817466cbSJens Wiklander {
362817466cbSJens Wiklander     memory_header *hdr, *old = NULL;
363817466cbSJens Wiklander     unsigned char *p = (unsigned char *) ptr;
364817466cbSJens Wiklander 
36532b31808SJens Wiklander     if (ptr == NULL || heap.buf == NULL || heap.first == NULL) {
366817466cbSJens Wiklander         return;
36732b31808SJens Wiklander     }
368817466cbSJens Wiklander 
36932b31808SJens Wiklander     if (p < heap.buf || p >= heap.buf + heap.len) {
370817466cbSJens Wiklander #if defined(MBEDTLS_MEMORY_DEBUG)
371817466cbSJens Wiklander         mbedtls_fprintf(stderr, "FATAL: mbedtls_free() outside of managed "
372817466cbSJens Wiklander                                 "space\n");
373817466cbSJens Wiklander #endif
374817466cbSJens Wiklander         mbedtls_exit(1);
375817466cbSJens Wiklander     }
376817466cbSJens Wiklander 
377817466cbSJens Wiklander     p -= sizeof(memory_header);
378817466cbSJens Wiklander     hdr = (memory_header *) p;
379817466cbSJens Wiklander 
38032b31808SJens Wiklander     if (verify_header(hdr) != 0) {
381817466cbSJens Wiklander         mbedtls_exit(1);
38232b31808SJens Wiklander     }
383817466cbSJens Wiklander 
38432b31808SJens Wiklander     if (hdr->alloc != 1) {
385817466cbSJens Wiklander #if defined(MBEDTLS_MEMORY_DEBUG)
386817466cbSJens Wiklander         mbedtls_fprintf(stderr, "FATAL: mbedtls_free() on unallocated "
387817466cbSJens Wiklander                                 "data\n");
388817466cbSJens Wiklander #endif
389817466cbSJens Wiklander         mbedtls_exit(1);
390817466cbSJens Wiklander     }
391817466cbSJens Wiklander 
392817466cbSJens Wiklander     hdr->alloc = 0;
393817466cbSJens Wiklander 
394817466cbSJens Wiklander #if defined(MBEDTLS_MEMORY_DEBUG)
395817466cbSJens Wiklander     heap.free_count++;
396817466cbSJens Wiklander     heap.total_used -= hdr->size;
397817466cbSJens Wiklander #endif
398817466cbSJens Wiklander 
399817466cbSJens Wiklander #if defined(MBEDTLS_MEMORY_BACKTRACE)
400817466cbSJens Wiklander     free(hdr->trace);
401817466cbSJens Wiklander     hdr->trace = NULL;
402817466cbSJens Wiklander     hdr->trace_count = 0;
403817466cbSJens Wiklander #endif
404817466cbSJens Wiklander 
405817466cbSJens Wiklander     // Regroup with block before
406817466cbSJens Wiklander     //
40732b31808SJens Wiklander     if (hdr->prev != NULL && hdr->prev->alloc == 0) {
408817466cbSJens Wiklander #if defined(MBEDTLS_MEMORY_DEBUG)
409817466cbSJens Wiklander         heap.header_count--;
410817466cbSJens Wiklander #endif
411817466cbSJens Wiklander         hdr->prev->size += sizeof(memory_header) + hdr->size;
412817466cbSJens Wiklander         hdr->prev->next = hdr->next;
413817466cbSJens Wiklander         old = hdr;
414817466cbSJens Wiklander         hdr = hdr->prev;
415817466cbSJens Wiklander 
41632b31808SJens Wiklander         if (hdr->next != NULL) {
417817466cbSJens Wiklander             hdr->next->prev = hdr;
41832b31808SJens Wiklander         }
419817466cbSJens Wiklander 
420817466cbSJens Wiklander         memset(old, 0, sizeof(memory_header));
421817466cbSJens Wiklander     }
422817466cbSJens Wiklander 
423817466cbSJens Wiklander     // Regroup with block after
424817466cbSJens Wiklander     //
42532b31808SJens Wiklander     if (hdr->next != NULL && hdr->next->alloc == 0) {
426817466cbSJens Wiklander #if defined(MBEDTLS_MEMORY_DEBUG)
427817466cbSJens Wiklander         heap.header_count--;
428817466cbSJens Wiklander #endif
429817466cbSJens Wiklander         hdr->size += sizeof(memory_header) + hdr->next->size;
430817466cbSJens Wiklander         old = hdr->next;
431817466cbSJens Wiklander         hdr->next = hdr->next->next;
432817466cbSJens Wiklander 
43332b31808SJens Wiklander         if (hdr->prev_free != NULL || hdr->next_free != NULL) {
43432b31808SJens Wiklander             if (hdr->prev_free != NULL) {
435817466cbSJens Wiklander                 hdr->prev_free->next_free = hdr->next_free;
43632b31808SJens Wiklander             } else {
437817466cbSJens Wiklander                 heap.first_free = hdr->next_free;
43832b31808SJens Wiklander             }
439817466cbSJens Wiklander 
44032b31808SJens Wiklander             if (hdr->next_free != NULL) {
441817466cbSJens Wiklander                 hdr->next_free->prev_free = hdr->prev_free;
442817466cbSJens Wiklander             }
44332b31808SJens Wiklander         }
444817466cbSJens Wiklander 
445817466cbSJens Wiklander         hdr->prev_free = old->prev_free;
446817466cbSJens Wiklander         hdr->next_free = old->next_free;
447817466cbSJens Wiklander 
44832b31808SJens Wiklander         if (hdr->prev_free != NULL) {
449817466cbSJens Wiklander             hdr->prev_free->next_free = hdr;
45032b31808SJens Wiklander         } else {
451817466cbSJens Wiklander             heap.first_free = hdr;
45232b31808SJens Wiklander         }
453817466cbSJens Wiklander 
45432b31808SJens Wiklander         if (hdr->next_free != NULL) {
455817466cbSJens Wiklander             hdr->next_free->prev_free = hdr;
45632b31808SJens Wiklander         }
457817466cbSJens Wiklander 
45832b31808SJens Wiklander         if (hdr->next != NULL) {
459817466cbSJens Wiklander             hdr->next->prev = hdr;
46032b31808SJens Wiklander         }
461817466cbSJens Wiklander 
462817466cbSJens Wiklander         memset(old, 0, sizeof(memory_header));
463817466cbSJens Wiklander     }
464817466cbSJens Wiklander 
465817466cbSJens Wiklander     // Prepend to free_list if we have not merged
466817466cbSJens Wiklander     // (Does not have to stay in same order as prev / next list)
467817466cbSJens Wiklander     //
46832b31808SJens Wiklander     if (old == NULL) {
469817466cbSJens Wiklander         hdr->next_free = heap.first_free;
47032b31808SJens Wiklander         if (heap.first_free != NULL) {
471817466cbSJens Wiklander             heap.first_free->prev_free = hdr;
47232b31808SJens Wiklander         }
473817466cbSJens Wiklander         heap.first_free = hdr;
474817466cbSJens Wiklander     }
475817466cbSJens Wiklander 
47632b31808SJens Wiklander     if ((heap.verify & MBEDTLS_MEMORY_VERIFY_FREE) && verify_chain() != 0) {
477817466cbSJens Wiklander         mbedtls_exit(1);
478817466cbSJens Wiklander     }
47932b31808SJens Wiklander }
480817466cbSJens Wiklander 
mbedtls_memory_buffer_set_verify(int verify)481817466cbSJens Wiklander void mbedtls_memory_buffer_set_verify(int verify)
482817466cbSJens Wiklander {
483817466cbSJens Wiklander     heap.verify = verify;
484817466cbSJens Wiklander }
485817466cbSJens Wiklander 
mbedtls_memory_buffer_alloc_verify(void)4863d3b0591SJens Wiklander int mbedtls_memory_buffer_alloc_verify(void)
487817466cbSJens Wiklander {
488817466cbSJens Wiklander     return verify_chain();
489817466cbSJens Wiklander }
490817466cbSJens Wiklander 
491817466cbSJens Wiklander #if defined(MBEDTLS_MEMORY_DEBUG)
mbedtls_memory_buffer_alloc_status(void)4923d3b0591SJens Wiklander void mbedtls_memory_buffer_alloc_status(void)
493817466cbSJens Wiklander {
494817466cbSJens Wiklander     mbedtls_fprintf(stderr,
495817466cbSJens Wiklander                     "Current use: %zu blocks / %zu bytes, max: %zu blocks / "
496817466cbSJens Wiklander                     "%zu bytes (total %zu bytes), alloc / free: %zu / %zu\n",
497817466cbSJens Wiklander                     heap.header_count, heap.total_used,
498817466cbSJens Wiklander                     heap.maximum_header_count, heap.maximum_used,
499817466cbSJens Wiklander                     heap.maximum_header_count * sizeof(memory_header)
500817466cbSJens Wiklander                     + heap.maximum_used,
501817466cbSJens Wiklander                     heap.alloc_count, heap.free_count);
502817466cbSJens Wiklander 
50332b31808SJens Wiklander     if (heap.first->next == NULL) {
504817466cbSJens Wiklander         mbedtls_fprintf(stderr, "All memory de-allocated in stack buffer\n");
50532b31808SJens Wiklander     } else {
506817466cbSJens Wiklander         mbedtls_fprintf(stderr, "Memory currently allocated:\n");
507817466cbSJens Wiklander         debug_chain();
508817466cbSJens Wiklander     }
509817466cbSJens Wiklander }
510817466cbSJens Wiklander 
mbedtls_memory_buffer_alloc_count_get(size_t * alloc_count,size_t * free_count)51132b31808SJens Wiklander void mbedtls_memory_buffer_alloc_count_get(size_t *alloc_count, size_t *free_count)
51232b31808SJens Wiklander {
51332b31808SJens Wiklander     *alloc_count = heap.alloc_count;
51432b31808SJens Wiklander     *free_count = heap.free_count;
51532b31808SJens Wiklander }
51632b31808SJens Wiklander 
mbedtls_memory_buffer_alloc_max_get(size_t * max_used,size_t * max_blocks)517817466cbSJens Wiklander void mbedtls_memory_buffer_alloc_max_get(size_t *max_used, size_t *max_blocks)
518817466cbSJens Wiklander {
519817466cbSJens Wiklander     *max_used   = heap.maximum_used;
520817466cbSJens Wiklander     *max_blocks = heap.maximum_header_count;
521817466cbSJens Wiklander }
522817466cbSJens Wiklander 
mbedtls_memory_buffer_alloc_max_reset(void)523817466cbSJens Wiklander void mbedtls_memory_buffer_alloc_max_reset(void)
524817466cbSJens Wiklander {
525817466cbSJens Wiklander     heap.maximum_used = 0;
526817466cbSJens Wiklander     heap.maximum_header_count = 0;
527817466cbSJens Wiklander }
528817466cbSJens Wiklander 
mbedtls_memory_buffer_alloc_cur_get(size_t * cur_used,size_t * cur_blocks)529817466cbSJens Wiklander void mbedtls_memory_buffer_alloc_cur_get(size_t *cur_used, size_t *cur_blocks)
530817466cbSJens Wiklander {
531817466cbSJens Wiklander     *cur_used   = heap.total_used;
532817466cbSJens Wiklander     *cur_blocks = heap.header_count;
533817466cbSJens Wiklander }
534817466cbSJens Wiklander #endif /* MBEDTLS_MEMORY_DEBUG */
535817466cbSJens Wiklander 
536817466cbSJens Wiklander #if defined(MBEDTLS_THREADING_C)
buffer_alloc_calloc_mutexed(size_t n,size_t size)537817466cbSJens Wiklander static void *buffer_alloc_calloc_mutexed(size_t n, size_t size)
538817466cbSJens Wiklander {
539817466cbSJens Wiklander     void *buf;
54032b31808SJens Wiklander     if (mbedtls_mutex_lock(&heap.mutex) != 0) {
54132b31808SJens Wiklander         return NULL;
54232b31808SJens Wiklander     }
543817466cbSJens Wiklander     buf = buffer_alloc_calloc(n, size);
54432b31808SJens Wiklander     if (mbedtls_mutex_unlock(&heap.mutex)) {
54532b31808SJens Wiklander         return NULL;
54632b31808SJens Wiklander     }
54732b31808SJens Wiklander     return buf;
548817466cbSJens Wiklander }
549817466cbSJens Wiklander 
buffer_alloc_free_mutexed(void * ptr)550817466cbSJens Wiklander static void buffer_alloc_free_mutexed(void *ptr)
551817466cbSJens Wiklander {
552039e02dfSJerome Forissier     /* We have no good option here, but corrupting the heap seems
553039e02dfSJerome Forissier      * worse than losing memory. */
55432b31808SJens Wiklander     if (mbedtls_mutex_lock(&heap.mutex)) {
555817466cbSJens Wiklander         return;
55632b31808SJens Wiklander     }
557817466cbSJens Wiklander     buffer_alloc_free(ptr);
558817466cbSJens Wiklander     (void) mbedtls_mutex_unlock(&heap.mutex);
559817466cbSJens Wiklander }
560817466cbSJens Wiklander #endif /* MBEDTLS_THREADING_C */
561817466cbSJens Wiklander 
mbedtls_memory_buffer_alloc_init(unsigned char * buf,size_t len)562817466cbSJens Wiklander void mbedtls_memory_buffer_alloc_init(unsigned char *buf, size_t len)
563817466cbSJens Wiklander {
564817466cbSJens Wiklander     memset(&heap, 0, sizeof(buffer_alloc_ctx));
565817466cbSJens Wiklander 
566817466cbSJens Wiklander #if defined(MBEDTLS_THREADING_C)
567817466cbSJens Wiklander     mbedtls_mutex_init(&heap.mutex);
568817466cbSJens Wiklander     mbedtls_platform_set_calloc_free(buffer_alloc_calloc_mutexed,
569817466cbSJens Wiklander                                      buffer_alloc_free_mutexed);
570817466cbSJens Wiklander #else
571817466cbSJens Wiklander     mbedtls_platform_set_calloc_free(buffer_alloc_calloc, buffer_alloc_free);
572817466cbSJens Wiklander #endif
573817466cbSJens Wiklander 
57432b31808SJens Wiklander     if (len < sizeof(memory_header) + MBEDTLS_MEMORY_ALIGN_MULTIPLE) {
5753d3b0591SJens Wiklander         return;
57632b31808SJens Wiklander     } else if ((size_t) buf % MBEDTLS_MEMORY_ALIGN_MULTIPLE) {
577817466cbSJens Wiklander         /* Adjust len first since buf is used in the computation */
578817466cbSJens Wiklander         len -= MBEDTLS_MEMORY_ALIGN_MULTIPLE
579817466cbSJens Wiklander                - (size_t) buf % MBEDTLS_MEMORY_ALIGN_MULTIPLE;
580817466cbSJens Wiklander         buf += MBEDTLS_MEMORY_ALIGN_MULTIPLE
581817466cbSJens Wiklander                - (size_t) buf % MBEDTLS_MEMORY_ALIGN_MULTIPLE;
582817466cbSJens Wiklander     }
583817466cbSJens Wiklander 
5843d3b0591SJens Wiklander     memset(buf, 0, len);
5853d3b0591SJens Wiklander 
586817466cbSJens Wiklander     heap.buf = buf;
587817466cbSJens Wiklander     heap.len = len;
588817466cbSJens Wiklander 
589817466cbSJens Wiklander     heap.first = (memory_header *) buf;
590817466cbSJens Wiklander     heap.first->size = len - sizeof(memory_header);
591817466cbSJens Wiklander     heap.first->magic1 = MAGIC1;
592817466cbSJens Wiklander     heap.first->magic2 = MAGIC2;
593817466cbSJens Wiklander     heap.first_free = heap.first;
594817466cbSJens Wiklander }
595817466cbSJens Wiklander 
mbedtls_memory_buffer_alloc_free(void)5963d3b0591SJens Wiklander void mbedtls_memory_buffer_alloc_free(void)
597817466cbSJens Wiklander {
598817466cbSJens Wiklander #if defined(MBEDTLS_THREADING_C)
599817466cbSJens Wiklander     mbedtls_mutex_free(&heap.mutex);
600817466cbSJens Wiklander #endif
6013d3b0591SJens Wiklander     mbedtls_platform_zeroize(&heap, sizeof(buffer_alloc_ctx));
602817466cbSJens Wiklander }
603817466cbSJens Wiklander 
604817466cbSJens Wiklander #if defined(MBEDTLS_SELF_TEST)
check_pointer(void * p)605817466cbSJens Wiklander static int check_pointer(void *p)
606817466cbSJens Wiklander {
60732b31808SJens Wiklander     if (p == NULL) {
60832b31808SJens Wiklander         return -1;
60932b31808SJens Wiklander     }
610817466cbSJens Wiklander 
61132b31808SJens Wiklander     if ((size_t) p % MBEDTLS_MEMORY_ALIGN_MULTIPLE != 0) {
61232b31808SJens Wiklander         return -1;
61332b31808SJens Wiklander     }
614817466cbSJens Wiklander 
61532b31808SJens Wiklander     return 0;
616817466cbSJens Wiklander }
617817466cbSJens Wiklander 
check_all_free(void)6183d3b0591SJens Wiklander static int check_all_free(void)
619817466cbSJens Wiklander {
620817466cbSJens Wiklander     if (
621817466cbSJens Wiklander #if defined(MBEDTLS_MEMORY_DEBUG)
622817466cbSJens Wiklander         heap.total_used != 0 ||
623817466cbSJens Wiklander #endif
624817466cbSJens Wiklander         heap.first != heap.first_free ||
62532b31808SJens Wiklander         (void *) heap.first != (void *) heap.buf) {
62632b31808SJens Wiklander         return -1;
627817466cbSJens Wiklander     }
628817466cbSJens Wiklander 
62932b31808SJens Wiklander     return 0;
630817466cbSJens Wiklander }
631817466cbSJens Wiklander 
632817466cbSJens Wiklander #define TEST_ASSERT(condition)            \
633817466cbSJens Wiklander     if (!(condition))                     \
634817466cbSJens Wiklander     {                                       \
635817466cbSJens Wiklander         if (verbose != 0)                  \
636817466cbSJens Wiklander         mbedtls_printf("failed\n");  \
637817466cbSJens Wiklander                                             \
638817466cbSJens Wiklander         ret = 1;                            \
639817466cbSJens Wiklander         goto cleanup;                       \
640817466cbSJens Wiklander     }
641817466cbSJens Wiklander 
mbedtls_memory_buffer_alloc_self_test(int verbose)642817466cbSJens Wiklander int mbedtls_memory_buffer_alloc_self_test(int verbose)
643817466cbSJens Wiklander {
644817466cbSJens Wiklander     unsigned char buf[1024];
645817466cbSJens Wiklander     unsigned char *p, *q, *r, *end;
646817466cbSJens Wiklander     int ret = 0;
647817466cbSJens Wiklander 
64832b31808SJens Wiklander     if (verbose != 0) {
649817466cbSJens Wiklander         mbedtls_printf("  MBA test #1 (basic alloc-free cycle): ");
65032b31808SJens Wiklander     }
651817466cbSJens Wiklander 
652817466cbSJens Wiklander     mbedtls_memory_buffer_alloc_init(buf, sizeof(buf));
653817466cbSJens Wiklander 
654817466cbSJens Wiklander     p = mbedtls_calloc(1, 1);
655817466cbSJens Wiklander     q = mbedtls_calloc(1, 128);
656817466cbSJens Wiklander     r = mbedtls_calloc(1, 16);
657817466cbSJens Wiklander 
658817466cbSJens Wiklander     TEST_ASSERT(check_pointer(p) == 0 &&
659817466cbSJens Wiklander                 check_pointer(q) == 0 &&
660817466cbSJens Wiklander                 check_pointer(r) == 0);
661817466cbSJens Wiklander 
662817466cbSJens Wiklander     mbedtls_free(r);
663817466cbSJens Wiklander     mbedtls_free(q);
664817466cbSJens Wiklander     mbedtls_free(p);
665817466cbSJens Wiklander 
666817466cbSJens Wiklander     TEST_ASSERT(check_all_free() == 0);
667817466cbSJens Wiklander 
668817466cbSJens Wiklander     /* Memorize end to compare with the next test */
669817466cbSJens Wiklander     end = heap.buf + heap.len;
670817466cbSJens Wiklander 
671817466cbSJens Wiklander     mbedtls_memory_buffer_alloc_free();
672817466cbSJens Wiklander 
67332b31808SJens Wiklander     if (verbose != 0) {
674817466cbSJens Wiklander         mbedtls_printf("passed\n");
67532b31808SJens Wiklander     }
676817466cbSJens Wiklander 
67732b31808SJens Wiklander     if (verbose != 0) {
678817466cbSJens Wiklander         mbedtls_printf("  MBA test #2 (buf not aligned): ");
67932b31808SJens Wiklander     }
680817466cbSJens Wiklander 
681817466cbSJens Wiklander     mbedtls_memory_buffer_alloc_init(buf + 1, sizeof(buf) - 1);
682817466cbSJens Wiklander 
683817466cbSJens Wiklander     TEST_ASSERT(heap.buf + heap.len == end);
684817466cbSJens Wiklander 
685817466cbSJens Wiklander     p = mbedtls_calloc(1, 1);
686817466cbSJens Wiklander     q = mbedtls_calloc(1, 128);
687817466cbSJens Wiklander     r = mbedtls_calloc(1, 16);
688817466cbSJens Wiklander 
689817466cbSJens Wiklander     TEST_ASSERT(check_pointer(p) == 0 &&
690817466cbSJens Wiklander                 check_pointer(q) == 0 &&
691817466cbSJens Wiklander                 check_pointer(r) == 0);
692817466cbSJens Wiklander 
693817466cbSJens Wiklander     mbedtls_free(r);
694817466cbSJens Wiklander     mbedtls_free(q);
695817466cbSJens Wiklander     mbedtls_free(p);
696817466cbSJens Wiklander 
697817466cbSJens Wiklander     TEST_ASSERT(check_all_free() == 0);
698817466cbSJens Wiklander 
699817466cbSJens Wiklander     mbedtls_memory_buffer_alloc_free();
700817466cbSJens Wiklander 
70132b31808SJens Wiklander     if (verbose != 0) {
702817466cbSJens Wiklander         mbedtls_printf("passed\n");
70332b31808SJens Wiklander     }
704817466cbSJens Wiklander 
70532b31808SJens Wiklander     if (verbose != 0) {
706817466cbSJens Wiklander         mbedtls_printf("  MBA test #3 (full): ");
70732b31808SJens Wiklander     }
708817466cbSJens Wiklander 
709817466cbSJens Wiklander     mbedtls_memory_buffer_alloc_init(buf, sizeof(buf));
710817466cbSJens Wiklander 
711817466cbSJens Wiklander     p = mbedtls_calloc(1, sizeof(buf) - sizeof(memory_header));
712817466cbSJens Wiklander 
713817466cbSJens Wiklander     TEST_ASSERT(check_pointer(p) == 0);
714817466cbSJens Wiklander     TEST_ASSERT(mbedtls_calloc(1, 1) == NULL);
715817466cbSJens Wiklander 
716817466cbSJens Wiklander     mbedtls_free(p);
717817466cbSJens Wiklander 
718817466cbSJens Wiklander     p = mbedtls_calloc(1, sizeof(buf) - 2 * sizeof(memory_header) - 16);
719817466cbSJens Wiklander     q = mbedtls_calloc(1, 16);
720817466cbSJens Wiklander 
721817466cbSJens Wiklander     TEST_ASSERT(check_pointer(p) == 0 && check_pointer(q) == 0);
722817466cbSJens Wiklander     TEST_ASSERT(mbedtls_calloc(1, 1) == NULL);
723817466cbSJens Wiklander 
724817466cbSJens Wiklander     mbedtls_free(q);
725817466cbSJens Wiklander 
726817466cbSJens Wiklander     TEST_ASSERT(mbedtls_calloc(1, 17) == NULL);
727817466cbSJens Wiklander 
728817466cbSJens Wiklander     mbedtls_free(p);
729817466cbSJens Wiklander 
730817466cbSJens Wiklander     TEST_ASSERT(check_all_free() == 0);
731817466cbSJens Wiklander 
732817466cbSJens Wiklander     mbedtls_memory_buffer_alloc_free();
733817466cbSJens Wiklander 
73432b31808SJens Wiklander     if (verbose != 0) {
735817466cbSJens Wiklander         mbedtls_printf("passed\n");
73632b31808SJens Wiklander     }
737817466cbSJens Wiklander 
738817466cbSJens Wiklander cleanup:
739817466cbSJens Wiklander     mbedtls_memory_buffer_alloc_free();
740817466cbSJens Wiklander 
74132b31808SJens Wiklander     return ret;
742817466cbSJens Wiklander }
743817466cbSJens Wiklander #endif /* MBEDTLS_SELF_TEST */
744817466cbSJens Wiklander 
745817466cbSJens Wiklander #endif /* MBEDTLS_MEMORY_BUFFER_ALLOC_C */
746