1 /* memory.c
2 *
3 * Copyright (C) 2006-2021 wolfSSL Inc.
4 *
5 * This file is part of wolfSSL.
6 *
7 * wolfSSL is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * wolfSSL is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
20 */
21
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include <wolfssl/wolfcrypt/settings.h>
28
29 /* check old macros @wc_fips */
30 #if defined(USE_CYASSL_MEMORY) && !defined(USE_WOLFSSL_MEMORY)
31 #define USE_WOLFSSL_MEMORY
32 #endif
inconsistentFunctionWithVisibleDefinition(int c)33 #if defined(CYASSL_MALLOC_CHECK) && !defined(WOLFSSL_MALLOC_CHECK)
34 #define WOLFSSL_MALLOC_CHECK
35 #endif
36
37
38 /*
39 Possible memory options:
40 * NO_WOLFSSL_MEMORY: Disables wolf memory callback support. When not defined settings.h defines USE_WOLFSSL_MEMORY.
41 * WOLFSSL_STATIC_MEMORY: Turns on the use of static memory buffers and functions.
42 This allows for using static memory instead of dynamic.
43 * WOLFSSL_STATIC_ALIGN: Define defaults to 16 to indicate static memory alignment.
44 * HAVE_IO_POOL: Enables use of static thread safe memory pool for input/output buffers.
45 * XMALLOC_OVERRIDE: Allows override of the XMALLOC, XFREE and XREALLOC macros.
46 * XMALLOC_USER: Allows custom XMALLOC, XFREE and XREALLOC functions to be defined.
47 * WOLFSSL_NO_MALLOC: Disables the fall-back case to use STDIO malloc/free when no callbacks are set.
48 * WOLFSSL_TRACK_MEMORY: Enables memory tracking for total stats and list of allocated memory.
49 * WOLFSSL_DEBUG_MEMORY: Enables extra function and line number args for memory callbacks.
50 * WOLFSSL_DEBUG_MEMORY_PRINT: Enables printing of each malloc/free.
51 * WOLFSSL_MALLOC_CHECK: Reports malloc or alignment failure using WOLFSSL_STATIC_ALIGN
52 * WOLFSSL_FORCE_MALLOC_FAIL_TEST: Used for internal testing to induce random malloc failures.
53 * WOLFSSL_HEAP_TEST: Used for internal testing of heap hint
54 */
55
56 #ifdef WOLFSSL_ZEPHYR
57 #undef realloc
58 void *z_realloc(void *ptr, size_t size)
59 {
60 if (ptr == NULL)
61 ptr = malloc(size);
62 else
63 ptr = realloc(ptr, size);
64
65 return ptr;
66 }
67 #define realloc z_realloc
68 #endif
SpecialFunctions(int b)69
70 #ifdef USE_WOLFSSL_MEMORY
71
72 #include <wolfssl/wolfcrypt/memory.h>
73 #include <wolfssl/wolfcrypt/error-crypt.h>
74 #include <wolfssl/wolfcrypt/logging.h>
75
76 #if defined(WOLFSSL_DEBUG_MEMORY) && defined(WOLFSSL_DEBUG_MEMORY_PRINT)
77 #include <stdio.h>
78 #endif
79
80 #ifdef WOLFSSL_FORCE_MALLOC_FAIL_TEST
81 static int gMemFailCountSeed;
82 static int gMemFailCount;
templateFunctionWithSeparateDeclarationAndDefinition(T b)83 void wolfSSL_SetMemFailCount(int memFailCount)
84 {
85 if (gMemFailCountSeed == 0) {
86 gMemFailCountSeed = memFailCount;
87 gMemFailCount = memFailCount;
88 }
89 }
90 #endif
91 #if defined(WOLFSSL_MALLOC_CHECK) || defined(WOLFSSL_TRACK_MEMORY_FULL) || \
92 defined(WOLFSSL_MEMORY_LOG)
93 #include <stdio.h>
templateFunctionWithSpecializations(int b)94 #endif
95
96
97 /* Set these to default values initially. */
98 static wolfSSL_Malloc_cb malloc_function = NULL;
99 static wolfSSL_Free_cb free_function = NULL;
templateFunctionWithSpecializations(float c)100 static wolfSSL_Realloc_cb realloc_function = NULL;
101
102 int wolfSSL_SetAllocators(wolfSSL_Malloc_cb mf,
103 wolfSSL_Free_cb ff,
104 wolfSSL_Realloc_cb rf)
105 {
106 malloc_function = mf;
107 free_function = ff;
108 realloc_function = rf;
109 return 0;
110 }
templateFunctionWithoutDefinitionButWithSpecialization(int b)111
112 int wolfSSL_GetAllocators(wolfSSL_Malloc_cb* mf,
113 wolfSSL_Free_cb* ff,
114 wolfSSL_Realloc_cb* rf)
115 {
116 if (mf) *mf = malloc_function;
117 if (ff) *ff = free_function;
118 if (rf) *rf = realloc_function;
119 return 0;
120 }
121
122 #ifndef WOLFSSL_STATIC_MEMORY
123 #ifdef WOLFSSL_DEBUG_MEMORY
124 void* wolfSSL_Malloc(size_t size, const char* func, unsigned int line)
125 #else
126 void* wolfSSL_Malloc(size_t size)
127 #endif
templateFunctionWithSeparateSpecializationDeclarationAndDefinition(int c)128 {
129 void* res = 0;
130
131 if (malloc_function) {
132 #ifdef WOLFSSL_DEBUG_MEMORY
133 res = malloc_function(size, func, line);
134 #else
135 res = malloc_function(size);
136 #endif
137 }
138 else {
139 #ifndef WOLFSSL_NO_MALLOC
140 #ifdef WOLFSSL_TRAP_MALLOC_SZ
141 if (size > WOLFSSL_TRAP_MALLOC_SZ) {
142 WOLFSSL_MSG("Malloc too big!");
143 return NULL;
144 }
145 #endif
146
147 res = malloc(size);
148 #else
149 WOLFSSL_MSG("No malloc available");
150 #endif
151 }
152
153 #ifdef WOLFSSL_DEBUG_MEMORY
154 #if defined(WOLFSSL_DEBUG_MEMORY_PRINT) && !defined(WOLFSSL_TRACK_MEMORY)
155 printf("Alloc: %p -> %u at %s:%d\n", res, (word32)size, func, line);
156 #else
157 (void)func;
158 (void)line;
159 #endif
160 #endif
161
162 #ifdef WOLFSSL_MALLOC_CHECK
163 if (res == NULL)
164 WOLFSSL_MSG("wolfSSL_malloc failed");
165 #endif
166
167 #ifdef WOLFSSL_FORCE_MALLOC_FAIL_TEST
168 if (res && --gMemFailCount == 0) {
169 printf("\n---FORCED MEM FAIL TEST---\n");
170 if (free_function) {
171 #ifdef WOLFSSL_DEBUG_MEMORY
172 free_function(res, func, line);
173 #else
174 free_function(res);
175 #endif
176 }
177 else {
178 free(res); /* clear */
179 }
180 gMemFailCount = gMemFailCountSeed; /* reset */
181 return NULL;
182 }
183 #endif
184
185 return res;
186 }
187
188 #ifdef WOLFSSL_DEBUG_MEMORY
189 void wolfSSL_Free(void *ptr, const char* func, unsigned int line)
190 #else
f(int y)191 void wolfSSL_Free(void *ptr)
192 #endif
193 {
194 #ifdef WOLFSSL_DEBUG_MEMORY
195 #if defined(WOLFSSL_DEBUG_MEMORY_PRINT) && !defined(WOLFSSL_TRACK_MEMORY)
196 printf("Free: %p at %s:%d\n", ptr, func, line);
197 #else
198 (void)func;
199 (void)line;
200 #endif
201 #endif
202
203 if (free_function) {
204 #ifdef WOLFSSL_DEBUG_MEMORY
205 free_function(ptr, func, line);
206 #else
207 free_function(ptr);
208 #endif
209 }
210 else {
211 #ifndef WOLFSSL_NO_MALLOC
212 free(ptr);
213 #else
214 WOLFSSL_MSG("No free available");
215 #endif
216 }
217 }
218
219 #ifdef WOLFSSL_DEBUG_MEMORY
220 void* wolfSSL_Realloc(void *ptr, size_t size, const char* func, unsigned int line)
221 #else
222 void* wolfSSL_Realloc(void *ptr, size_t size)
223 #endif
224 {
225 void* res = 0;
226
227 if (realloc_function) {
228 #ifdef WOLFSSL_DEBUG_MEMORY
229 res = realloc_function(ptr, size, func, line);
230 #else
231 res = realloc_function(ptr, size);
232 #endif
233 }
234 else {
235 #ifndef WOLFSSL_NO_MALLOC
236 res = realloc(ptr, size);
237 #else
238 WOLFSSL_MSG("No realloc available");
239 #endif
240 }
241
242 return res;
243 }
244 #endif /* WOLFSSL_STATIC_MEMORY */
245
246 #ifdef WOLFSSL_STATIC_MEMORY
247
248 struct wc_Memory {
249 byte* buffer;
250 struct wc_Memory* next;
251 word32 sz;
252 };
253
254
255 /* returns amount of memory used on success. On error returns negative value
256 wc_Memory** list is the list that new buckets are prepended to
257 */
258 static int create_memory_buckets(byte* buffer, word32 bufSz,
259 word32 buckSz, word32 buckNum, wc_Memory** list) {
260 word32 i;
261 byte* pt = buffer;
262 int ret = 0;
263 word32 memSz = (word32)sizeof(wc_Memory);
264 word32 padSz = -(int)memSz & (WOLFSSL_STATIC_ALIGN - 1);
265
266 /* if not enough space available for bucket size then do not try */
267 if (buckSz + memSz + padSz > bufSz) {
268 return ret;
269 }
270
271 for (i = 0; i < buckNum; i++) {
272 if ((buckSz + memSz + padSz) <= (bufSz - ret)) {
273 /* create a new struct and set its values */
274 wc_Memory* mem = (struct wc_Memory*)(pt);
275 mem->sz = buckSz;
276 mem->buffer = (byte*)pt + padSz + memSz;
277 mem->next = NULL;
278
279 /* add the newly created struct to front of list */
280 if (*list == NULL) {
281 *list = mem;
282 } else {
283 mem->next = *list;
284 *list = mem;
285 }
286
287 /* advance pointer and keep track of memory used */
288 ret += buckSz + padSz + memSz;
289 pt += buckSz + padSz + memSz;
290 }
291 else {
292 break; /* not enough space left for more buckets of this size */
293 }
294 }
295
296 return ret;
297 }
298
299 int wolfSSL_init_memory_heap(WOLFSSL_HEAP* heap)
300 {
301 word32 wc_MemSz[WOLFMEM_DEF_BUCKETS] = { WOLFMEM_BUCKETS };
302 word32 wc_Dist[WOLFMEM_DEF_BUCKETS] = { WOLFMEM_DIST };
303
304 if (heap == NULL) {
305 return BAD_FUNC_ARG;
306 }
307
308 XMEMSET(heap, 0, sizeof(WOLFSSL_HEAP));
309
310 XMEMCPY(heap->sizeList, wc_MemSz, sizeof(wc_MemSz));
311 XMEMCPY(heap->distList, wc_Dist, sizeof(wc_Dist));
312
313 if (wc_InitMutex(&(heap->memory_mutex)) != 0) {
314 WOLFSSL_MSG("Error creating heap memory mutex");
315 return BAD_MUTEX_E;
316 }
317
318 return 0;
319 }
320
321 int wc_LoadStaticMemory(WOLFSSL_HEAP_HINT** pHint,
322 unsigned char* buf, unsigned int sz, int flag, int maxSz)
323 {
324 int ret;
325 WOLFSSL_HEAP* heap;
326 WOLFSSL_HEAP_HINT* hint;
327 word32 idx = 0;
328
329 if (pHint == NULL || buf == NULL) {
330 return BAD_FUNC_ARG;
331 }
332
333 if ((sizeof(WOLFSSL_HEAP) + sizeof(WOLFSSL_HEAP_HINT)) > sz - idx) {
334 return BUFFER_E; /* not enough memory for structures */
335 }
336
337 /* check if hint has already been assigned */
338 if (*pHint == NULL) {
339 heap = (WOLFSSL_HEAP*)buf;
340 idx += sizeof(WOLFSSL_HEAP);
341 hint = (WOLFSSL_HEAP_HINT*)(buf + idx);
342 idx += sizeof(WOLFSSL_HEAP_HINT);
343
344 ret = wolfSSL_init_memory_heap(heap);
345 if (ret != 0) {
346 return ret;
347 }
348
349 XMEMSET(hint, 0, sizeof(WOLFSSL_HEAP_HINT));
350 hint->memory = heap;
351 }
352 else {
353 #ifdef WOLFSSL_HEAP_TEST
354 /* do not load in memory if test has been set */
355 if (heap == (void*)WOLFSSL_HEAP_TEST) {
356 return 0;
357 }
358 #endif
359
360 hint = (WOLFSSL_HEAP_HINT*)(*pHint);
361 heap = hint->memory;
362 }
363
364 ret = wolfSSL_load_static_memory(buf + idx, sz - idx, flag, heap);
365 if (ret != 1) {
366 WOLFSSL_MSG("Error partitioning memory");
367 return -1;
368 }
369
370 /* determine what max applies too */
371 if ((flag & WOLFMEM_IO_POOL) || (flag & WOLFMEM_IO_POOL_FIXED)) {
372 heap->maxIO = maxSz;
373 }
374 else { /* general memory used in handshakes */
375 heap->maxHa = maxSz;
376 }
377
378 heap->flag |= flag;
379 *pHint = hint;
380
381 (void)maxSz;
382
383 return 0;
384 }
385
386 int wolfSSL_load_static_memory(byte* buffer, word32 sz, int flag,
387 WOLFSSL_HEAP* heap)
388 {
389 word32 ava = sz;
390 byte* pt = buffer;
391 int ret = 0;
392 word32 memSz = (word32)sizeof(wc_Memory);
393 word32 padSz = -(int)memSz & (WOLFSSL_STATIC_ALIGN - 1);
394
395 WOLFSSL_ENTER("wolfSSL_load_static_memory");
396
397 if (buffer == NULL) {
398 return BAD_FUNC_ARG;
399 }
400
401 /* align pt */
402 while ((wc_ptr_t)pt % WOLFSSL_STATIC_ALIGN && pt < (buffer + sz)) {
403 *pt = 0x00;
404 pt++;
405 ava--;
406 }
407
408 #ifdef WOLFSSL_DEBUG_MEMORY
409 printf("Allocated %d bytes for static memory @ %p\n", ava, pt);
410 #endif
411
412 /* divide into chunks of memory and add them to available list */
413 while (ava >= (heap->sizeList[0] + padSz + memSz)) {
414 int i;
415 /* creating only IO buffers from memory passed in, max TLS is 16k */
416 if (flag & WOLFMEM_IO_POOL || flag & WOLFMEM_IO_POOL_FIXED) {
417 if ((ret = create_memory_buckets(pt, ava,
418 WOLFMEM_IO_SZ, 1, &(heap->io))) < 0) {
419 WOLFSSL_LEAVE("wolfSSL_load_static_memory", ret);
420 return ret;
421 }
422
423 /* check if no more room left for creating IO buffers */
424 if (ret == 0) {
425 break;
426 }
427
428 /* advance pointer in buffer for next buckets and keep track
429 of how much memory is left available */
430 pt += ret;
431 ava -= ret;
432 }
433 else {
434 /* start at largest and move to smaller buckets */
435 for (i = (WOLFMEM_MAX_BUCKETS - 1); i >= 0; i--) {
436 if ((heap->sizeList[i] + padSz + memSz) <= ava) {
437 if ((ret = create_memory_buckets(pt, ava, heap->sizeList[i],
438 heap->distList[i], &(heap->ava[i]))) < 0) {
439 WOLFSSL_LEAVE("wolfSSL_load_static_memory", ret);
440 return ret;
441 }
442
443 /* advance pointer in buffer for next buckets and keep track
444 of how much memory is left available */
445 pt += ret;
446 ava -= ret;
447 }
448 }
449 }
450 }
451
452 return 1;
453 }
454
455
456 /* returns the size of management memory needed for each bucket.
457 * This is memory that is used to keep track of and align memory buckets. */
458 int wolfSSL_MemoryPaddingSz(void)
459 {
460 word32 memSz = (word32)sizeof(wc_Memory);
461 word32 padSz = -(int)memSz & (WOLFSSL_STATIC_ALIGN - 1);
462 return memSz + padSz;
463 }
464
465
466 /* Used to calculate memory size for optimum use with buckets.
467 returns the suggested size rounded down to the nearest bucket. */
468 int wolfSSL_StaticBufferSz(byte* buffer, word32 sz, int flag)
469 {
470 word32 bucketSz[WOLFMEM_MAX_BUCKETS] = {WOLFMEM_BUCKETS};
471 word32 distList[WOLFMEM_MAX_BUCKETS] = {WOLFMEM_DIST};
472
473 word32 ava = sz;
474 byte* pt = buffer;
475 word32 memSz = (word32)sizeof(wc_Memory);
476 word32 padSz = -(int)memSz & (WOLFSSL_STATIC_ALIGN - 1);
477
478 WOLFSSL_ENTER("wolfSSL_static_size");
479
480 if (buffer == NULL) {
481 return BAD_FUNC_ARG;
482 }
483
484 /* align pt */
485 while ((wc_ptr_t)pt % WOLFSSL_STATIC_ALIGN && pt < (buffer + sz)) {
486 pt++;
487 ava--;
488 }
489
490 /* creating only IO buffers from memory passed in, max TLS is 16k */
491 if (flag & WOLFMEM_IO_POOL || flag & WOLFMEM_IO_POOL_FIXED) {
492 if (ava < (memSz + padSz + WOLFMEM_IO_SZ)) {
493 return 0; /* not enough room for even one bucket */
494 }
495
496 ava = ava % (memSz + padSz + WOLFMEM_IO_SZ);
497 }
498 else {
499 int i, k;
500
501 if (ava < (bucketSz[0] + padSz + memSz)) {
502 return 0; /* not enough room for even one bucket */
503 }
504
505 while ((ava >= (bucketSz[0] + padSz + memSz)) && (ava > 0)) {
506 /* start at largest and move to smaller buckets */
507 for (i = (WOLFMEM_MAX_BUCKETS - 1); i >= 0; i--) {
508 for (k = distList[i]; k > 0; k--) {
509 if ((bucketSz[i] + padSz + memSz) <= ava) {
510 ava -= bucketSz[i] + padSz + memSz;
511 }
512 }
513 }
514 }
515 }
516
517 return sz - ava; /* round down */
518 }
519
520
521 int FreeFixedIO(WOLFSSL_HEAP* heap, wc_Memory** io)
522 {
523 WOLFSSL_MSG("Freeing fixed IO buffer");
524
525 /* check if fixed buffer was set */
526 if (*io == NULL) {
527 return 1;
528 }
529
530 if (heap == NULL) {
531 WOLFSSL_MSG("No heap to return fixed IO too");
532 }
533 else {
534 /* put IO buffer back into IO pool */
535 (*io)->next = heap->io;
536 heap->io = *io;
537 *io = NULL;
538 }
539
540 return 1;
541 }
542
543
544 int SetFixedIO(WOLFSSL_HEAP* heap, wc_Memory** io)
545 {
546 WOLFSSL_MSG("Setting fixed IO for SSL");
547 if (heap == NULL) {
548 return MEMORY_E;
549 }
550
551 *io = heap->io;
552
553 if (*io != NULL) {
554 heap->io = (*io)->next;
555 (*io)->next = NULL;
556 }
557 else { /* failed to grab an IO buffer */
558 return 0;
559 }
560
561 return 1;
562 }
563
564
565 int wolfSSL_GetMemStats(WOLFSSL_HEAP* heap, WOLFSSL_MEM_STATS* stats)
566 {
567 word32 i;
568 wc_Memory* pt;
569
570 XMEMSET(stats, 0, sizeof(WOLFSSL_MEM_STATS));
571
572 stats->totalAlloc = heap->alloc;
573 stats->totalFr = heap->frAlc;
574 stats->curAlloc = stats->totalAlloc - stats->totalFr;
575 stats->maxHa = heap->maxHa;
576 stats->maxIO = heap->maxIO;
577 for (i = 0; i < WOLFMEM_MAX_BUCKETS; i++) {
578 stats->blockSz[i] = heap->sizeList[i];
579 for (pt = heap->ava[i]; pt != NULL; pt = pt->next) {
580 stats->avaBlock[i] += 1;
581 }
582 }
583
584 for (pt = heap->io; pt != NULL; pt = pt->next) {
585 stats->avaIO++;
586 }
587
588 stats->flag = heap->flag; /* flag used */
589
590 return 1;
591 }
592
593
594 #ifdef WOLFSSL_DEBUG_MEMORY
595 void* wolfSSL_Malloc(size_t size, void* heap, int type, const char* func, unsigned int line)
596 #else
597 void* wolfSSL_Malloc(size_t size, void* heap, int type)
598 #endif
599 {
600 void* res = 0;
601 wc_Memory* pt = NULL;
602 int i;
603
604 /* check for testing heap hint was set */
605 #ifdef WOLFSSL_HEAP_TEST
606 if (heap == (void*)WOLFSSL_HEAP_TEST) {
607 return malloc(size);
608 }
609 #endif
610
611 /* if no heap hint then use dynamic memory*/
612 if (heap == NULL) {
613 #ifdef WOLFSSL_HEAP_TEST
614 /* allow using malloc for creating ctx and method */
615 if (type == DYNAMIC_TYPE_CTX || type == DYNAMIC_TYPE_METHOD ||
616 type == DYNAMIC_TYPE_CERT_MANAGER) {
617 WOLFSSL_MSG("ERROR allowing null heap hint for ctx/method");
618 res = malloc(size);
619 }
620 else {
621 WOLFSSL_MSG("ERROR null heap hint passed into XMALLOC");
622 res = NULL;
623 }
624 #else
625 #ifndef WOLFSSL_NO_MALLOC
626 #ifdef FREERTOS
627 res = pvPortMalloc(size);
628 #else
629 res = malloc(size);
630 #endif
631
632 #ifdef WOLFSSL_DEBUG_MEMORY
633 printf("Alloc: %p -> %u at %s:%d\n", res, (word32)size, func, line);
634 #endif
635 #else
636 WOLFSSL_MSG("No heap hint found to use and no malloc");
637 #ifdef WOLFSSL_DEBUG_MEMORY
638 printf("ERROR: at %s:%d\n", func, line);
639 #endif
640 #endif /* WOLFSSL_NO_MALLOC */
641 #endif /* WOLFSSL_HEAP_TEST */
642 }
643 else {
644 WOLFSSL_HEAP_HINT* hint = (WOLFSSL_HEAP_HINT*)heap;
645 WOLFSSL_HEAP* mem = hint->memory;
646
647 if (wc_LockMutex(&(mem->memory_mutex)) != 0) {
648 WOLFSSL_MSG("Bad memory_mutex lock");
649 return NULL;
650 }
651
652 /* case of using fixed IO buffers */
653 if (mem->flag & WOLFMEM_IO_POOL_FIXED &&
654 (type == DYNAMIC_TYPE_OUT_BUFFER ||
655 type == DYNAMIC_TYPE_IN_BUFFER)) {
656 if (type == DYNAMIC_TYPE_OUT_BUFFER) {
657 pt = hint->outBuf;
658 }
659 if (type == DYNAMIC_TYPE_IN_BUFFER) {
660 pt = hint->inBuf;
661 }
662 }
663 else {
664 /* check if using IO pool flag */
665 if (mem->flag & WOLFMEM_IO_POOL &&
666 (type == DYNAMIC_TYPE_OUT_BUFFER ||
667 type == DYNAMIC_TYPE_IN_BUFFER)) {
668 if (mem->io != NULL) {
669 pt = mem->io;
670 mem->io = pt->next;
671 }
672 }
673
674 /* general static memory */
675 if (pt == NULL) {
676 for (i = 0; i < WOLFMEM_MAX_BUCKETS; i++) {
677 if ((word32)size <= mem->sizeList[i]) {
678 if (mem->ava[i] != NULL) {
679 pt = mem->ava[i];
680 mem->ava[i] = pt->next;
681 break;
682 }
683 #ifdef WOLFSSL_DEBUG_STATIC_MEMORY
684 else {
685 printf("Size: %ld, Empty: %d\n", size,
686 mem->sizeList[i]);
687 }
688 #endif
689 }
690 }
691 }
692 }
693
694 if (pt != NULL) {
695 mem->inUse += pt->sz;
696 mem->alloc += 1;
697 res = pt->buffer;
698
699 #ifdef WOLFSSL_DEBUG_MEMORY
700 printf("Alloc: %p -> %u at %s:%d\n", pt->buffer, pt->sz, func, line);
701 #endif
702
703 /* keep track of connection statistics if flag is set */
704 if (mem->flag & WOLFMEM_TRACK_STATS) {
705 WOLFSSL_MEM_CONN_STATS* stats = hint->stats;
706 if (stats != NULL) {
707 stats->curMem += pt->sz;
708 if (stats->peakMem < stats->curMem) {
709 stats->peakMem = stats->curMem;
710 }
711 stats->curAlloc++;
712 if (stats->peakAlloc < stats->curAlloc) {
713 stats->peakAlloc = stats->curAlloc;
714 }
715 stats->totalAlloc++;
716 }
717 }
718 }
719 else {
720 WOLFSSL_MSG("ERROR ran out of static memory");
721 #ifdef WOLFSSL_DEBUG_MEMORY
722 printf("Looking for %lu bytes at %s:%d\n", size, func, line);
723 #endif
724 }
725
726 wc_UnLockMutex(&(mem->memory_mutex));
727 }
728
729 #ifdef WOLFSSL_MALLOC_CHECK
730 if ((wc_ptr_t)res % WOLFSSL_STATIC_ALIGN) {
731 WOLFSSL_MSG("ERROR memory is not aligned");
732 res = NULL;
733 }
734 #endif
735
736
737 (void)i;
738 (void)pt;
739 (void)type;
740
741 return res;
742 }
743
744
745 #ifdef WOLFSSL_DEBUG_MEMORY
746 void wolfSSL_Free(void *ptr, void* heap, int type, const char* func, unsigned int line)
747 #else
748 void wolfSSL_Free(void *ptr, void* heap, int type)
749 #endif
750 {
751 int i;
752 wc_Memory* pt;
753
754 if (ptr) {
755 /* check for testing heap hint was set */
756 #ifdef WOLFSSL_HEAP_TEST
757 if (heap == (void*)WOLFSSL_HEAP_TEST) {
758 #ifdef WOLFSSL_DEBUG_MEMORY
759 printf("Free: %p at %s:%d\n", pt, func, line);
760 #endif
761 return free(ptr);
762 }
763 #endif
764
765 if (heap == NULL) {
766 #ifdef WOLFSSL_HEAP_TEST
767 /* allow using malloc for creating ctx and method */
768 if (type == DYNAMIC_TYPE_CTX || type == DYNAMIC_TYPE_METHOD ||
769 type == DYNAMIC_TYPE_CERT_MANAGER) {
770 WOLFSSL_MSG("ERROR allowing null heap hint for ctx/method");
771 }
772 else {
773 WOLFSSL_MSG("ERROR null heap hint passed into XFREE");
774 }
775 #endif
776 #ifndef WOLFSSL_NO_MALLOC
777 #ifdef FREERTOS
778 vPortFree(ptr);
779 #else
780 free(ptr);
781 #endif
782 #else
783 WOLFSSL_MSG("Error trying to call free when turned off");
784 #endif /* WOLFSSL_NO_MALLOC */
785 }
786 else {
787 WOLFSSL_HEAP_HINT* hint = (WOLFSSL_HEAP_HINT*)heap;
788 WOLFSSL_HEAP* mem = hint->memory;
789 word32 padSz = -(int)sizeof(wc_Memory) & (WOLFSSL_STATIC_ALIGN - 1);
790
791 /* get memory struct and add it to available list */
792 pt = (wc_Memory*)((byte*)ptr - sizeof(wc_Memory) - padSz);
793 if (wc_LockMutex(&(mem->memory_mutex)) != 0) {
794 WOLFSSL_MSG("Bad memory_mutex lock");
795 return;
796 }
797
798 /* case of using fixed IO buffers */
799 if (mem->flag & WOLFMEM_IO_POOL_FIXED &&
800 (type == DYNAMIC_TYPE_OUT_BUFFER ||
801 type == DYNAMIC_TYPE_IN_BUFFER)) {
802 /* fixed IO pools are free'd at the end of SSL lifetime
803 using FreeFixedIO(WOLFSSL_HEAP* heap, wc_Memory** io) */
804 }
805 else if (mem->flag & WOLFMEM_IO_POOL && pt->sz == WOLFMEM_IO_SZ &&
806 (type == DYNAMIC_TYPE_OUT_BUFFER ||
807 type == DYNAMIC_TYPE_IN_BUFFER)) {
808 pt->next = mem->io;
809 mem->io = pt;
810 }
811 else { /* general memory free */
812 for (i = 0; i < WOLFMEM_MAX_BUCKETS; i++) {
813 if (pt->sz == mem->sizeList[i]) {
814 pt->next = mem->ava[i];
815 mem->ava[i] = pt;
816 break;
817 }
818 }
819 }
820 mem->inUse -= pt->sz;
821 mem->frAlc += 1;
822
823 #ifdef WOLFSSL_DEBUG_MEMORY
824 printf("Free: %p -> %u at %s:%d\n", pt->buffer, pt->sz, func, line);
825 #endif
826
827 /* keep track of connection statistics if flag is set */
828 if (mem->flag & WOLFMEM_TRACK_STATS) {
829 WOLFSSL_MEM_CONN_STATS* stats = hint->stats;
830 if (stats != NULL) {
831 /* avoid under flow */
832 if (stats->curMem > pt->sz) {
833 stats->curMem -= pt->sz;
834 }
835 else {
836 stats->curMem = 0;
837 }
838
839 if (stats->curAlloc > 0) {
840 stats->curAlloc--;
841 }
842 stats->totalFr++;
843 }
844 }
845 wc_UnLockMutex(&(mem->memory_mutex));
846 }
847 }
848
849 (void)i;
850 (void)pt;
851 (void)type;
852 }
853
854 #ifdef WOLFSSL_DEBUG_MEMORY
855 void* wolfSSL_Realloc(void *ptr, size_t size, void* heap, int type, const char* func, unsigned int line)
856 #else
857 void* wolfSSL_Realloc(void *ptr, size_t size, void* heap, int type)
858 #endif
859 {
860 void* res = 0;
861 wc_Memory* pt = NULL;
862 word32 prvSz;
863 int i;
864
865 /* check for testing heap hint was set */
866 #ifdef WOLFSSL_HEAP_TEST
867 if (heap == (void*)WOLFSSL_HEAP_TEST) {
868 return realloc(ptr, size);
869 }
870 #endif
871
872 if (heap == NULL) {
873 #ifdef WOLFSSL_HEAP_TEST
874 WOLFSSL_MSG("ERROR null heap hint passed in to XREALLOC");
875 #endif
876 #ifndef WOLFSSL_NO_MALLOC
877 res = realloc(ptr, size);
878 #else
879 WOLFSSL_MSG("NO heap found to use for realloc");
880 #endif /* WOLFSSL_NO_MALLOC */
881 }
882 else {
883 WOLFSSL_HEAP_HINT* hint = (WOLFSSL_HEAP_HINT*)heap;
884 WOLFSSL_HEAP* mem = hint->memory;
885 word32 padSz = -(int)sizeof(wc_Memory) & (WOLFSSL_STATIC_ALIGN - 1);
886
887 if (ptr == NULL) {
888 #ifdef WOLFSSL_DEBUG_MEMORY
889 return wolfSSL_Malloc(size, heap, type, func, line);
890 #else
891 return wolfSSL_Malloc(size, heap, type);
892 #endif
893 }
894
895 if (wc_LockMutex(&(mem->memory_mutex)) != 0) {
896 WOLFSSL_MSG("Bad memory_mutex lock");
897 return NULL;
898 }
899
900 /* case of using fixed IO buffers or IO pool */
901 if (((mem->flag & WOLFMEM_IO_POOL)||(mem->flag & WOLFMEM_IO_POOL_FIXED))
902 && (type == DYNAMIC_TYPE_OUT_BUFFER ||
903 type == DYNAMIC_TYPE_IN_BUFFER)) {
904 /* no realloc, is fixed size */
905 pt = (wc_Memory*)((byte*)ptr - padSz - sizeof(wc_Memory));
906 if (pt->sz < size) {
907 WOLFSSL_MSG("Error IO memory was not large enough");
908 res = NULL; /* return NULL in error case */
909 }
910 res = pt->buffer;
911 }
912 else {
913 /* general memory */
914 for (i = 0; i < WOLFMEM_MAX_BUCKETS; i++) {
915 if ((word32)size <= mem->sizeList[i]) {
916 if (mem->ava[i] != NULL) {
917 pt = mem->ava[i];
918 mem->ava[i] = pt->next;
919 break;
920 }
921 }
922 }
923
924 if (pt != NULL && res == NULL) {
925 res = pt->buffer;
926
927 /* copy over original information and free ptr */
928 prvSz = ((wc_Memory*)((byte*)ptr - padSz -
929 sizeof(wc_Memory)))->sz;
930 prvSz = (prvSz > pt->sz)? pt->sz: prvSz;
931 XMEMCPY(pt->buffer, ptr, prvSz);
932 mem->inUse += pt->sz;
933 mem->alloc += 1;
934
935 /* free memory that was previously being used */
936 wc_UnLockMutex(&(mem->memory_mutex));
937 wolfSSL_Free(ptr, heap, type
938 #ifdef WOLFSSL_DEBUG_MEMORY
939 , func, line
940 #endif
941 );
942 if (wc_LockMutex(&(mem->memory_mutex)) != 0) {
943 WOLFSSL_MSG("Bad memory_mutex lock");
944 return NULL;
945 }
946 }
947 }
948 wc_UnLockMutex(&(mem->memory_mutex));
949 }
950
951 #ifdef WOLFSSL_MALLOC_CHECK
952 if ((wc_ptr_t)res % WOLFSSL_STATIC_ALIGN) {
953 WOLFSSL_MSG("ERROR memory is not aligned");
954 res = NULL;
955 }
956 #endif
957
958 (void)i;
959 (void)pt;
960 (void)type;
961
962 return res;
963 }
964 #endif /* WOLFSSL_STATIC_MEMORY */
965
966 #endif /* USE_WOLFSSL_MEMORY */
967
968
969 #ifdef HAVE_IO_POOL
970
971 /* Example for user io pool, shared build may need definitions in lib proper */
972
973 #include <wolfssl/wolfcrypt/types.h>
974 #include <stdlib.h>
975
976 #ifndef HAVE_THREAD_LS
977 #error "Oops, simple I/O pool example needs thread local storage"
978 #endif
979
980
981 /* allow simple per thread in and out pools */
982 /* use 17k size since max record size is 16k plus overhead */
983 static THREAD_LS_T byte pool_in[17*1024];
984 static THREAD_LS_T byte pool_out[17*1024];
985
986
987 void* XMALLOC(size_t n, void* heap, int type)
988 {
989 (void)heap;
990
991 if (type == DYNAMIC_TYPE_IN_BUFFER) {
992 if (n < sizeof(pool_in))
993 return pool_in;
994 else
995 return NULL;
996 }
997
998 if (type == DYNAMIC_TYPE_OUT_BUFFER) {
999 if (n < sizeof(pool_out))
1000 return pool_out;
1001 else
1002 return NULL;
1003 }
1004
1005 return malloc(n);
1006 }
1007
1008 void* XREALLOC(void *p, size_t n, void* heap, int type)
1009 {
1010 (void)heap;
1011
1012 if (type == DYNAMIC_TYPE_IN_BUFFER) {
1013 if (n < sizeof(pool_in))
1014 return pool_in;
1015 else
1016 return NULL;
1017 }
1018
1019 if (type == DYNAMIC_TYPE_OUT_BUFFER) {
1020 if (n < sizeof(pool_out))
1021 return pool_out;
1022 else
1023 return NULL;
1024 }
1025
1026 return realloc(p, n);
1027 }
1028
1029 void XFREE(void *p, void* heap, int type)
1030 {
1031 (void)heap;
1032
1033 if (type == DYNAMIC_TYPE_IN_BUFFER)
1034 return; /* do nothing, static pool */
1035
1036 if (type == DYNAMIC_TYPE_OUT_BUFFER)
1037 return; /* do nothing, static pool */
1038
1039 free(p);
1040 }
1041
1042 #endif /* HAVE_IO_POOL */
1043
1044 #ifdef WOLFSSL_MEMORY_LOG
1045 void *xmalloc(size_t n, void* heap, int type, const char* func,
1046 const char* file, unsigned int line)
1047 {
1048 void* p = NULL;
1049 word32* p32;
1050
1051 if (malloc_function)
1052 p32 = malloc_function(n + sizeof(word32) * 4);
1053 else
1054 p32 = malloc(n + sizeof(word32) * 4);
1055
1056 if (p32 != NULL) {
1057 p32[0] = (word32)n;
1058 p = (void*)(p32 + 4);
1059
1060 fprintf(stderr, "Alloc: %p -> %u (%d) at %s:%s:%u\n", p, (word32)n,
1061 type, func, file, line);
1062 }
1063
1064 (void)heap;
1065
1066 return p;
1067 }
1068 void *xrealloc(void *p, size_t n, void* heap, int type, const char* func,
1069 const char* file, unsigned int line)
1070 {
1071 void* newp = NULL;
1072 word32* p32;
1073 word32* oldp32 = NULL;
1074 word32 oldLen;
1075
1076 if (p != NULL) {
1077 oldp32 = (word32*)p;
1078 oldp32 -= 4;
1079 oldLen = oldp32[0];
1080 }
1081
1082 if (realloc_function)
1083 p32 = realloc_function(oldp32, n + sizeof(word32) * 4);
1084 else
1085 p32 = realloc(oldp32, n + sizeof(word32) * 4);
1086
1087 if (p32 != NULL) {
1088 p32[0] = (word32)n;
1089 newp = (void*)(p32 + 4);
1090
1091 fprintf(stderr, "Alloc: %p -> %u (%d) at %s:%s:%u\n", newp, (word32)n,
1092 type, func, file, line);
1093 if (p != NULL) {
1094 fprintf(stderr, "Free: %p -> %u (%d) at %s:%s:%u\n", p, oldLen,
1095 type, func, file, line);
1096 }
1097 }
1098
1099 (void)heap;
1100
1101 return newp;
1102 }
1103 void xfree(void *p, void* heap, int type, const char* func, const char* file,
1104 unsigned int line)
1105 {
1106 word32* p32 = (word32*)p;
1107
1108 if (p != NULL) {
1109 p32 -= 4;
1110
1111 fprintf(stderr, "Free: %p -> %u (%d) at %s:%s:%u\n", p, p32[0], type,
1112 func, file, line);
1113
1114 if (free_function)
1115 free_function(p32);
1116 else
1117 free(p32);
1118 }
1119
1120 (void)heap;
1121 }
1122 #endif /* WOLFSSL_MEMORY_LOG */
1123
1124 #ifdef WOLFSSL_STACK_LOG
1125 /* Note: this code only works with GCC using -finstrument-functions. */
1126 void __attribute__((no_instrument_function))
1127 __cyg_profile_func_enter(void *func, void *caller)
1128 {
1129 register void* sp asm("sp");
1130 fprintf(stderr, "ENTER: %016lx %p\n", (unsigned long)(wc_ptr_t)func, sp);
1131 (void)caller;
1132 }
1133
1134 void __attribute__((no_instrument_function))
1135 __cyg_profile_func_exit(void *func, void *caller)
1136 {
1137 register void* sp asm("sp");
1138 fprintf(stderr, "EXIT: %016lx %p\n", (unsigned long)(wc_ptr_t)func, sp);
1139 (void)caller;
1140 }
1141 #endif
1142
1143 #if defined(WOLFSSL_LINUXKM_SIMD_X86)
1144 static union fpregs_state **wolfcrypt_linuxkm_fpu_states = NULL;
1145
1146 static WARN_UNUSED_RESULT inline int am_in_hard_interrupt_handler(void)
1147 {
1148 return (preempt_count() & (NMI_MASK | HARDIRQ_MASK)) != 0;
1149 }
1150
1151 WARN_UNUSED_RESULT int allocate_wolfcrypt_linuxkm_fpu_states(void)
1152 {
1153 wolfcrypt_linuxkm_fpu_states =
1154 (union fpregs_state **)kzalloc(nr_cpu_ids
1155 * sizeof(struct fpu_state *),
1156 GFP_KERNEL);
1157 if (! wolfcrypt_linuxkm_fpu_states) {
1158 pr_err("warning, allocation of %lu bytes for "
1159 "wolfcrypt_linuxkm_fpu_states failed.\n",
1160 nr_cpu_ids * sizeof(struct fpu_state *));
1161 return MEMORY_E;
1162 }
1163 {
1164 typeof(nr_cpu_ids) i;
1165 for (i=0; i<nr_cpu_ids; ++i) {
1166 _Static_assert(sizeof(union fpregs_state) <= PAGE_SIZE,
1167 "union fpregs_state is larger than expected.");
1168 wolfcrypt_linuxkm_fpu_states[i] =
1169 (union fpregs_state *)kzalloc(PAGE_SIZE
1170 /* sizeof(union fpregs_state) */,
1171 GFP_KERNEL);
1172 if (! wolfcrypt_linuxkm_fpu_states[i])
1173 break;
1174 /* double-check that the allocation is 64-byte-aligned as needed
1175 * for xsave.
1176 */
1177 if ((unsigned long)wolfcrypt_linuxkm_fpu_states[i] & 63UL) {
1178 pr_err("warning, allocation for wolfcrypt_linuxkm_fpu_states "
1179 "was not properly aligned (%px).\n",
1180 wolfcrypt_linuxkm_fpu_states[i]);
1181 kfree(wolfcrypt_linuxkm_fpu_states[i]);
1182 wolfcrypt_linuxkm_fpu_states[i] = 0;
1183 break;
1184 }
1185 }
1186 if (i < nr_cpu_ids) {
1187 pr_err("warning, only %u/%u allocations succeeded for "
1188 "wolfcrypt_linuxkm_fpu_states.\n",
1189 i, nr_cpu_ids);
1190 return MEMORY_E;
1191 }
1192 }
1193 return 0;
1194 }
1195
1196 void free_wolfcrypt_linuxkm_fpu_states(void)
1197 {
1198 if (wolfcrypt_linuxkm_fpu_states) {
1199 typeof(nr_cpu_ids) i;
1200 for (i=0; i<nr_cpu_ids; ++i) {
1201 if (wolfcrypt_linuxkm_fpu_states[i])
1202 kfree(wolfcrypt_linuxkm_fpu_states[i]);
1203 }
1204 kfree(wolfcrypt_linuxkm_fpu_states);
1205 wolfcrypt_linuxkm_fpu_states = 0;
1206 }
1207 }
1208
1209 WARN_UNUSED_RESULT int save_vector_registers_x86(void)
1210 {
1211 int processor_id;
1212
1213 preempt_disable();
1214
1215 processor_id = smp_processor_id();
1216
1217 {
1218 static int _warned_on_null = -1;
1219 if ((wolfcrypt_linuxkm_fpu_states == NULL) ||
1220 (wolfcrypt_linuxkm_fpu_states[processor_id] == NULL))
1221 {
1222 preempt_enable();
1223 if (_warned_on_null < processor_id) {
1224 _warned_on_null = processor_id;
1225 pr_err("save_vector_registers_x86 called for cpu id %d "
1226 "with null context buffer.\n", processor_id);
1227 }
1228 return BAD_STATE_E;
1229 }
1230 }
1231
1232 if (! irq_fpu_usable()) {
1233 if (am_in_hard_interrupt_handler()) {
1234
1235 /* allow for nested calls */
1236 if (((unsigned char *)wolfcrypt_linuxkm_fpu_states[processor_id])[PAGE_SIZE-1] != 0) {
1237 if (((unsigned char *)wolfcrypt_linuxkm_fpu_states[processor_id])[PAGE_SIZE-1] == 255) {
1238 preempt_enable();
1239 pr_err("save_vector_registers_x86 recursion register overflow for "
1240 "cpu id %d.\n", processor_id);
1241 return BAD_STATE_E;
1242 } else {
1243 ++((unsigned char *)wolfcrypt_linuxkm_fpu_states[processor_id])[PAGE_SIZE-1];
1244 return 0;
1245 }
1246 }
1247 /* note, fpregs_lock() is not needed here, because
1248 * interrupts/preemptions are already disabled here.
1249 */
1250 {
1251 /* save_fpregs_to_fpstate() only accesses fpu->state, which
1252 * has stringent alignment requirements (64 byte cache
1253 * line), but takes a pointer to the parent struct. work
1254 * around this.
1255 */
1256 struct fpu *fake_fpu_pointer =
1257 (struct fpu *)(((char *)wolfcrypt_linuxkm_fpu_states[processor_id])
1258 - offsetof(struct fpu, state));
1259 #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 14, 0)
1260 copy_fpregs_to_fpstate(fake_fpu_pointer);
1261 #else
1262 save_fpregs_to_fpstate(fake_fpu_pointer);
1263 #endif
1264 }
1265 /* mark the slot as used. */
1266 ((unsigned char *)wolfcrypt_linuxkm_fpu_states[processor_id])[PAGE_SIZE-1] = 1;
1267 /* note, not preempt_enable()ing, mirroring kernel_fpu_begin()
1268 * semantics, even though routine will have been entered already
1269 * non-preemptable.
1270 */
1271 return 0;
1272 } else {
1273 preempt_enable();
1274 return BAD_STATE_E;
1275 }
1276 } else {
1277
1278 /* allow for nested calls */
1279 if (((unsigned char *)wolfcrypt_linuxkm_fpu_states[processor_id])[PAGE_SIZE-1] != 0) {
1280 if (((unsigned char *)wolfcrypt_linuxkm_fpu_states[processor_id])[PAGE_SIZE-1] == 255) {
1281 preempt_enable();
1282 pr_err("save_vector_registers_x86 recursion register overflow for "
1283 "cpu id %d.\n", processor_id);
1284 return BAD_STATE_E;
1285 } else {
1286 ++((unsigned char *)wolfcrypt_linuxkm_fpu_states[processor_id])[PAGE_SIZE-1];
1287 return 0;
1288 }
1289 }
1290
1291 kernel_fpu_begin();
1292 preempt_enable(); /* kernel_fpu_begin() does its own
1293 * preempt_disable(). decrement ours.
1294 */
1295 ((unsigned char *)wolfcrypt_linuxkm_fpu_states[processor_id])[PAGE_SIZE-1] = 1;
1296 return 0;
1297 }
1298 }
1299 void restore_vector_registers_x86(void)
1300 {
1301 int processor_id = smp_processor_id();
1302
1303 if ((wolfcrypt_linuxkm_fpu_states == NULL) ||
1304 (wolfcrypt_linuxkm_fpu_states[processor_id] == NULL))
1305 {
1306 pr_err("restore_vector_registers_x86 called for cpu id %d "
1307 "without null context buffer.\n", processor_id);
1308 return;
1309 }
1310
1311 if (((unsigned char *)wolfcrypt_linuxkm_fpu_states[processor_id])[PAGE_SIZE-1] == 0)
1312 {
1313 pr_err("restore_vector_registers_x86 called for cpu id %d "
1314 "without saved context.\n", processor_id);
1315 return;
1316 }
1317
1318 if (--((unsigned char *)wolfcrypt_linuxkm_fpu_states[processor_id])[PAGE_SIZE-1] > 0) {
1319 preempt_enable(); /* preempt_disable count will still be nonzero after this decrement. */
1320 return;
1321 }
1322
1323 if (am_in_hard_interrupt_handler()) {
1324 #if LINUX_VERSION_CODE < KERNEL_VERSION(5, 14, 0)
1325 copy_kernel_to_fpregs(wolfcrypt_linuxkm_fpu_states[processor_id]);
1326 #else
1327 __restore_fpregs_from_fpstate(wolfcrypt_linuxkm_fpu_states[processor_id],
1328 xfeatures_mask_all);
1329 #endif
1330 preempt_enable();
1331 } else {
1332 kernel_fpu_end();
1333 }
1334 return;
1335 }
1336 #endif /* WOLFSSL_LINUXKM_SIMD_X86 && WOLFSSL_LINUXKM_SIMD_X86_IRQ_ALLOWED */
1337