1 // SPDX-License-Identifier: BSD-2-Clause 2 /* 3 * Copyright (c) 2014, STMicroelectronics International N.V. 4 * Copyright (c) 2015-2025, Linaro Limited. 5 */ 6 7 #define PROTOTYPES 8 9 /* 10 * BGET CONFIGURATION 11 * ================== 12 */ 13 /* #define BGET_ENABLE_ALL_OPTIONS */ 14 #ifdef BGET_ENABLE_OPTION 15 #define TestProg 20000 /* Generate built-in test program 16 if defined. The value specifies 17 how many buffer allocation attempts 18 the test program should make. */ 19 #endif 20 21 22 #ifdef __LP64__ 23 #define SizeQuant 16 24 #endif 25 #ifdef __ILP32__ 26 #define SizeQuant 8 27 #endif 28 /* Buffer allocation size quantum: 29 all buffers allocated are a 30 multiple of this size. This 31 MUST be a power of two. */ 32 33 #ifdef BGET_ENABLE_OPTION 34 #define BufDump 1 /* Define this symbol to enable the 35 bpoold() function which dumps the 36 buffers in a buffer pool. */ 37 38 #define BufValid 1 /* Define this symbol to enable the 39 bpoolv() function for validating 40 a buffer pool. */ 41 42 #define DumpData 1 /* Define this symbol to enable the 43 bufdump() function which allows 44 dumping the contents of an allocated 45 or free buffer. */ 46 47 #define BufStats 1 /* Define this symbol to enable the 48 bstats() function which calculates 49 the total free space in the buffer 50 pool, the largest available 51 buffer, and the total space 52 currently allocated. */ 53 54 #define FreeWipe 1 /* Wipe free buffers to a guaranteed 55 pattern of garbage to trip up 56 miscreants who attempt to use 57 pointers into released buffers. */ 58 59 #define BestFit 1 /* Use a best fit algorithm when 60 searching for space for an 61 allocation request. This uses 62 memory more efficiently, but 63 allocation will be much slower. */ 64 65 #define BECtl 1 /* Define this symbol to enable the 66 bectl() function for automatic 67 pool space control. */ 68 #endif 69 70 #ifdef MEM_DEBUG 71 #undef NDEBUG 72 #define DumpData 1 73 #define BufValid 1 74 #define FreeWipe 1 75 #endif 76 77 #ifdef CFG_WITH_STATS 78 #define BufStats 1 79 #endif 80 81 #include <compiler.h> 82 #include <config.h> 83 #include <malloc.h> 84 #include <memtag.h> 85 #include <pta_stats.h> 86 #include <stdbool.h> 87 #include <stdint.h> 88 #include <stdlib_ext.h> 89 #include <stdlib.h> 90 #include <string.h> 91 #include <trace.h> 92 #include <util.h> 93 94 #if defined(__KERNEL__) 95 /* Compiling for TEE Core */ 96 #include <kernel/asan.h> 97 #include <kernel/spinlock.h> 98 #include <kernel/unwind.h> 99 100 static void *memset_unchecked(void *s, int c, size_t n) 101 { 102 return asan_memset_unchecked(s, c, n); 103 } 104 105 static __maybe_unused void *memcpy_unchecked(void *dst, const void *src, 106 size_t n) 107 { 108 return asan_memcpy_unchecked(dst, src, n); 109 } 110 111 #else /*__KERNEL__*/ 112 /* Compiling for TA */ 113 114 static void *memset_unchecked(void *s, int c, size_t n) 115 { 116 return memset(s, c, n); 117 } 118 119 static __maybe_unused void *memcpy_unchecked(void *dst, const void *src, 120 size_t n) 121 { 122 return memcpy(dst, src, n); 123 } 124 125 #endif /*__KERNEL__*/ 126 127 #include "bget.c" /* this is ugly, but this is bget */ 128 129 struct malloc_pool { 130 void *buf; 131 size_t len; 132 }; 133 134 struct malloc_ctx { 135 struct bpoolset poolset; 136 struct malloc_pool *pool; 137 size_t pool_len; 138 #ifdef BufStats 139 struct pta_stats_alloc mstats; 140 #endif 141 #ifdef __KERNEL__ 142 unsigned int spinlock; 143 #endif 144 }; 145 146 #ifdef __KERNEL__ 147 148 static uint32_t malloc_lock(struct malloc_ctx *ctx) 149 { 150 return cpu_spin_lock_xsave(&ctx->spinlock); 151 } 152 153 static void malloc_unlock(struct malloc_ctx *ctx, uint32_t exceptions) 154 { 155 cpu_spin_unlock_xrestore(&ctx->spinlock, exceptions); 156 } 157 158 #else /* __KERNEL__ */ 159 160 static uint32_t malloc_lock(struct malloc_ctx *ctx __unused) 161 { 162 return 0; 163 } 164 165 static void malloc_unlock(struct malloc_ctx *ctx __unused, 166 uint32_t exceptions __unused) 167 { 168 } 169 170 #endif /* __KERNEL__ */ 171 172 #define DEFINE_CTX(name) struct malloc_ctx name = \ 173 { .poolset = { .freelist = { {0, 0}, \ 174 {&name.poolset.freelist, \ 175 &name.poolset.freelist}}}} 176 177 static DEFINE_CTX(malloc_ctx); 178 179 #ifdef CFG_NS_VIRTUALIZATION 180 static __nex_data DEFINE_CTX(nex_malloc_ctx); 181 #endif 182 183 static void print_oom(size_t req_size __maybe_unused, void *ctx __maybe_unused) 184 { 185 #if defined(__KERNEL__) && defined(CFG_CORE_DUMP_OOM) 186 EMSG("Memory allocation failed: size %zu context %p", req_size, ctx); 187 print_kernel_stack(); 188 #endif 189 } 190 191 /* Most of the stuff in this function is copied from bgetr() in bget.c */ 192 static __maybe_unused bufsize bget_buf_size(void *buf) 193 { 194 bufsize osize; /* Old size of buffer */ 195 struct bhead *b; 196 197 b = BH(((char *)buf) - sizeof(struct bhead)); 198 osize = -b->bsize; 199 #ifdef BECtl 200 if (osize == 0) { 201 /* Buffer acquired directly through acqfcn. */ 202 struct bdhead *bd; 203 204 bd = BDH(((char *)buf) - sizeof(struct bdhead)); 205 osize = bd->tsize - sizeof(struct bdhead) - bd->offs; 206 } else 207 #endif 208 osize -= sizeof(struct bhead); 209 assert(osize > 0); 210 return osize; 211 } 212 213 static void *maybe_tag_buf(uint8_t *buf, size_t hdr_size, size_t requested_size) 214 { 215 if (!buf) 216 return NULL; 217 218 COMPILE_TIME_ASSERT(MEMTAG_GRANULE_SIZE <= SizeQuant); 219 220 if (MEMTAG_IS_ENABLED) { 221 size_t sz = 0; 222 223 /* 224 * MEMTAG needs actual allocated size (>= SizeQuant), 225 * unlike ASan which tags only requested bytes. For 226 * malloc(0), bget allocates SizeQuant, so we pass 227 * MAX(requested_size, SizeQuant) to ensure correct tagging. 228 */ 229 requested_size = MAX(requested_size, SizeQuant); 230 231 sz = ROUNDUP(requested_size, MEMTAG_GRANULE_SIZE); 232 233 /* 234 * Allocated buffer can be larger than requested when 235 * allocating with memalign(), but we should never tag more 236 * than allocated. 237 */ 238 assert(bget_buf_size(buf) >= sz + hdr_size); 239 return memtag_set_random_tags(buf, sz + hdr_size); 240 } 241 242 #if defined(__KERNEL__) 243 asan_tag_access(buf, buf + hdr_size + requested_size); 244 #endif 245 return buf; 246 } 247 248 static void *maybe_untag_buf(void *buf) 249 { 250 if (!buf) 251 return NULL; 252 253 if (MEMTAG_IS_ENABLED) { 254 size_t sz = 0; 255 256 memtag_assert_tag(buf); /* Trying to catch double free early */ 257 sz = bget_buf_size(memtag_strip_tag(buf)); 258 return memtag_set_tags(buf, sz, 0); 259 } 260 261 #if defined(__KERNEL__) 262 asan_tag_heap_free(buf, (uint8_t *)buf + bget_buf_size(buf)); 263 #endif 264 return buf; 265 } 266 267 static void *strip_tag(void *buf) 268 { 269 if (MEMTAG_IS_ENABLED) 270 return memtag_strip_tag(buf); 271 return buf; 272 } 273 274 static void tag_asan_free(void *buf __maybe_unused, size_t len __maybe_unused) 275 { 276 #if defined(__KERNEL__) 277 asan_tag_heap_free(buf, (uint8_t *)buf + len); 278 #endif 279 } 280 281 #ifdef BufStats 282 283 static void *raw_malloc_return_hook(void *p, size_t hdr_size, 284 size_t requested_size, 285 struct malloc_ctx *ctx) 286 { 287 if (ctx->poolset.totalloc > ctx->mstats.max_allocated) 288 ctx->mstats.max_allocated = ctx->poolset.totalloc; 289 290 if (!p) { 291 ctx->mstats.num_alloc_fail++; 292 print_oom(requested_size, ctx); 293 if (requested_size > ctx->mstats.biggest_alloc_fail) { 294 ctx->mstats.biggest_alloc_fail = requested_size; 295 ctx->mstats.biggest_alloc_fail_used = 296 ctx->poolset.totalloc; 297 } 298 } 299 300 return maybe_tag_buf(p, hdr_size, requested_size); 301 } 302 303 static void gen_malloc_reset_stats(struct malloc_ctx *ctx) 304 { 305 uint32_t exceptions = malloc_lock(ctx); 306 307 ctx->mstats.max_allocated = 0; 308 ctx->mstats.num_alloc_fail = 0; 309 ctx->mstats.biggest_alloc_fail = 0; 310 ctx->mstats.biggest_alloc_fail_used = 0; 311 malloc_unlock(ctx, exceptions); 312 } 313 314 void malloc_reset_stats(void) 315 { 316 gen_malloc_reset_stats(&malloc_ctx); 317 } 318 319 static void gen_malloc_get_stats(struct malloc_ctx *ctx, 320 struct pta_stats_alloc *stats) 321 { 322 uint32_t exceptions = malloc_lock(ctx); 323 324 raw_malloc_get_stats(ctx, stats); 325 malloc_unlock(ctx, exceptions); 326 } 327 328 void malloc_get_stats(struct pta_stats_alloc *stats) 329 { 330 gen_malloc_get_stats(&malloc_ctx, stats); 331 } 332 333 #else /* BufStats */ 334 335 static void *raw_malloc_return_hook(void *p, size_t hdr_size, 336 size_t requested_size, 337 struct malloc_ctx *ctx ) 338 { 339 if (!p) 340 print_oom(requested_size, ctx); 341 342 return maybe_tag_buf(p, hdr_size, requested_size); 343 } 344 345 #endif /* BufStats */ 346 347 #ifdef BufValid 348 static void raw_malloc_validate_pools(struct malloc_ctx *ctx) 349 { 350 size_t n; 351 352 for (n = 0; n < ctx->pool_len; n++) 353 bpoolv(ctx->pool[n].buf); 354 } 355 #else 356 static void raw_malloc_validate_pools(struct malloc_ctx *ctx __unused) 357 { 358 } 359 #endif 360 361 struct bpool_iterator { 362 struct bfhead *next_buf; 363 size_t pool_idx; 364 }; 365 366 static void bpool_foreach_iterator_init(struct malloc_ctx *ctx, 367 struct bpool_iterator *iterator) 368 { 369 iterator->pool_idx = 0; 370 iterator->next_buf = BFH(ctx->pool[0].buf); 371 } 372 373 static bool bpool_foreach_pool(struct bpool_iterator *iterator, void **buf, 374 size_t *len, bool *isfree) 375 { 376 struct bfhead *b = iterator->next_buf; 377 bufsize bs = b->bh.bsize; 378 379 if (bs == ESent) 380 return false; 381 382 if (bs < 0) { 383 /* Allocated buffer */ 384 bs = -bs; 385 386 *isfree = false; 387 } else { 388 /* Free Buffer */ 389 *isfree = true; 390 391 /* Assert that the free list links are intact */ 392 assert(b->ql.blink->ql.flink == b); 393 assert(b->ql.flink->ql.blink == b); 394 } 395 396 *buf = (uint8_t *)b + sizeof(struct bhead); 397 *len = bs - sizeof(struct bhead); 398 399 iterator->next_buf = BFH((uint8_t *)b + bs); 400 return true; 401 } 402 403 static bool bpool_foreach(struct malloc_ctx *ctx, 404 struct bpool_iterator *iterator, void **buf) 405 { 406 while (true) { 407 size_t len; 408 bool isfree; 409 410 if (bpool_foreach_pool(iterator, buf, &len, &isfree)) { 411 if (isfree) 412 continue; 413 return true; 414 } 415 416 if ((iterator->pool_idx + 1) >= ctx->pool_len) 417 return false; 418 419 iterator->pool_idx++; 420 iterator->next_buf = BFH(ctx->pool[iterator->pool_idx].buf); 421 } 422 } 423 424 /* Convenience macro for looping over all allocated buffers */ 425 #define BPOOL_FOREACH(ctx, iterator, bp) \ 426 for (bpool_foreach_iterator_init((ctx),(iterator)); \ 427 bpool_foreach((ctx),(iterator), (bp));) 428 429 void *raw_malloc_flags(uint32_t flags, void *ptr, size_t hdr_size, 430 size_t ftr_size, size_t alignment, size_t pl_nmemb, 431 size_t pl_size, struct malloc_ctx *ctx) 432 { 433 void *p = NULL; 434 bufsize s = 0; 435 436 raw_malloc_validate_pools(ctx); 437 438 if (!alignment || !IS_POWER_OF_TWO(alignment)) 439 return NULL; 440 441 /* Compute total size, excluding hdr_size */ 442 if (MUL_OVERFLOW(pl_nmemb, pl_size, &s)) 443 goto out; 444 if (ADD_OVERFLOW(s, ftr_size, &s)) 445 goto out; 446 447 /* BGET doesn't like 0 sized allocations */ 448 if (!s) 449 s++; 450 451 if ((flags & MAF_ZERO_INIT) && !ptr) 452 p = bgetz(alignment, hdr_size, s, &ctx->poolset); 453 else 454 p = bget(alignment, hdr_size, s, &ctx->poolset); 455 456 if (p && ptr) { 457 void *old_ptr = maybe_untag_buf(ptr); 458 bufsize old_sz = bget_buf_size(old_ptr); 459 bufsize new_sz = s + hdr_size; 460 461 if (old_sz < new_sz) { 462 memcpy_unchecked(p, old_ptr, old_sz); 463 if (flags & MAF_ZERO_INIT) 464 memset_unchecked((uint8_t *)p + old_sz, 0, 465 new_sz - old_sz); 466 } else { 467 memcpy_unchecked(p, old_ptr, new_sz); 468 } 469 470 brel(old_ptr, &ctx->poolset, false /*!wipe*/); 471 } 472 out: 473 return raw_malloc_return_hook(p, hdr_size, pl_nmemb * pl_size, ctx); 474 } 475 476 void *raw_memalign(size_t hdr_size, size_t ftr_size, size_t alignment, 477 size_t pl_size, struct malloc_ctx *ctx) 478 { 479 return raw_malloc_flags(MAF_NULL, NULL, hdr_size, ftr_size, alignment, 480 1, pl_size, ctx); 481 } 482 483 void *raw_malloc(size_t hdr_size, size_t ftr_size, size_t pl_size, 484 struct malloc_ctx *ctx) 485 { 486 return raw_malloc_flags(MAF_NULL, NULL, hdr_size, ftr_size, 1, 1, 487 pl_size, ctx); 488 } 489 490 void raw_free(void *ptr, struct malloc_ctx *ctx, bool wipe) 491 { 492 raw_malloc_validate_pools(ctx); 493 494 if (ptr) 495 brel(maybe_untag_buf(ptr), &ctx->poolset, wipe); 496 } 497 498 void *raw_calloc(size_t hdr_size, size_t ftr_size, size_t pl_nmemb, 499 size_t pl_size, struct malloc_ctx *ctx) 500 { 501 return raw_malloc_flags(MAF_ZERO_INIT, NULL, hdr_size, ftr_size, 1, 502 pl_nmemb, pl_size, ctx); 503 } 504 505 void *raw_realloc(void *ptr, size_t hdr_size, size_t ftr_size, 506 size_t pl_size, struct malloc_ctx *ctx) 507 { 508 return raw_malloc_flags(MAF_NULL, ptr, hdr_size, ftr_size, 1, 1, 509 pl_size, ctx); 510 } 511 512 struct mdbg_hdr { 513 const char *fname; 514 uint16_t line; 515 #ifdef __LP64__ 516 uint64_t pad; 517 #endif 518 uint32_t pl_size; 519 uint32_t magic; 520 }; 521 522 #define MDBG_HEADER_MAGIC 0xadadadad 523 #define MDBG_FOOTER_MAGIC 0xecececec 524 525 static size_t mdbg_get_ftr_size(size_t pl_size) 526 { 527 size_t ftr_pad = ROUNDUP(pl_size, sizeof(uint32_t)) - pl_size; 528 529 return ftr_pad + sizeof(uint32_t); 530 } 531 532 static uint32_t *mdbg_get_footer(struct mdbg_hdr *hdr) 533 { 534 uint32_t *footer; 535 536 footer = (uint32_t *)((uint8_t *)(hdr + 1) + hdr->pl_size + 537 mdbg_get_ftr_size(hdr->pl_size)); 538 footer--; 539 return strip_tag(footer); 540 } 541 542 static void mdbg_update_hdr(struct mdbg_hdr *hdr, const char *fname, 543 int lineno, size_t pl_size) 544 { 545 uint32_t *footer; 546 547 hdr->fname = fname; 548 hdr->line = lineno; 549 hdr->pl_size = pl_size; 550 hdr->magic = MDBG_HEADER_MAGIC; 551 552 footer = mdbg_get_footer(hdr); 553 *footer = MDBG_FOOTER_MAGIC; 554 } 555 556 static void assert_header(struct mdbg_hdr *hdr __maybe_unused) 557 { 558 assert(hdr->magic == MDBG_HEADER_MAGIC); 559 assert(*mdbg_get_footer(hdr) == MDBG_FOOTER_MAGIC); 560 } 561 562 static void *mem_alloc_unlocked(uint32_t flags, void *ptr, size_t alignment, 563 size_t nmemb, size_t size, const char *fname, 564 int lineno, struct malloc_ctx *ctx) 565 { 566 struct mdbg_hdr *hdr = NULL; 567 size_t ftr_size = 0; 568 size_t hdr_size = 0; 569 570 /* 571 * Check struct mdbg_hdr works with BGET_HDR_QUANTUM. 572 */ 573 static_assert((sizeof(struct mdbg_hdr) % BGET_HDR_QUANTUM) == 0); 574 575 if (IS_ENABLED2(ENABLE_MDBG)) { 576 if (ptr) { 577 hdr = ptr; 578 hdr--; 579 assert_header(hdr); 580 } 581 ftr_size = mdbg_get_ftr_size(nmemb * size); 582 hdr_size = sizeof(struct mdbg_hdr); 583 ptr = hdr; 584 } 585 586 ptr = raw_malloc_flags(flags, ptr, hdr_size, ftr_size, alignment, nmemb, 587 size, ctx); 588 589 if (IS_ENABLED2(ENABLE_MDBG) && ptr) { 590 hdr = ptr; 591 mdbg_update_hdr(hdr, fname, lineno, nmemb * size); 592 hdr++; 593 ptr = hdr; 594 } 595 596 return ptr; 597 } 598 599 static struct malloc_ctx *get_ctx(uint32_t flags __maybe_unused) 600 { 601 #ifdef CFG_NS_VIRTUALIZATION 602 if (flags & MAF_NEX) 603 return &nex_malloc_ctx; 604 #endif 605 return &malloc_ctx; 606 } 607 608 static void *mem_alloc(uint32_t flags, void *ptr, size_t alignment, 609 size_t nmemb, size_t size, const char *fname, int lineno) 610 { 611 struct malloc_ctx *ctx = get_ctx(flags); 612 uint32_t exceptions = 0; 613 void *p = NULL; 614 615 exceptions = malloc_lock(ctx); 616 p = mem_alloc_unlocked(flags, ptr, alignment, nmemb, size, fname, 617 lineno, ctx); 618 malloc_unlock(ctx, exceptions); 619 620 return p; 621 } 622 623 void free_flags(uint32_t flags, void *ptr) 624 { 625 struct malloc_ctx *ctx = get_ctx(flags); 626 uint32_t exceptions = 0; 627 628 exceptions = malloc_lock(ctx); 629 630 if (IS_ENABLED2(ENABLE_MDBG) && ptr) { 631 struct mdbg_hdr *hdr = ptr; 632 633 hdr--; 634 assert_header(hdr); 635 hdr->magic = 0; 636 *mdbg_get_footer(hdr) = 0; 637 ptr = hdr; 638 } 639 640 raw_free(ptr, ctx, flags & MAF_FREE_WIPE); 641 642 malloc_unlock(ctx, exceptions); 643 } 644 645 static void *get_payload_start_size(void *raw_buf, size_t *size) 646 { 647 if (IS_ENABLED2(ENABLE_MDBG)) { 648 struct mdbg_hdr *hdr = raw_buf; 649 650 assert(bget_buf_size(hdr) >= hdr->pl_size); 651 *size = hdr->pl_size; 652 return hdr + 1; 653 } 654 655 *size = bget_buf_size(raw_buf); 656 return raw_buf; 657 } 658 659 /* For use in raw_malloc_add_pool() below */ 660 #define realloc_unlocked(ctx, ptr, size) \ 661 mem_alloc_unlocked(MAF_NULL, (ptr), 1, 1, (size), __FILE__, __LINE__, \ 662 (ctx)) 663 664 #ifdef ENABLE_MDBG 665 void *__mdbg_alloc(uint32_t flags, void *ptr, size_t alignment, size_t nmemb, 666 size_t size, const char *fname, int lineno) 667 { 668 return mem_alloc(flags, ptr, alignment, nmemb, size, fname, lineno); 669 } 670 671 static void gen_mdbg_check(struct malloc_ctx *ctx, int bufdump) 672 { 673 struct bpool_iterator itr; 674 void *b; 675 uint32_t exceptions = malloc_lock(ctx); 676 677 raw_malloc_validate_pools(ctx); 678 679 BPOOL_FOREACH(ctx, &itr, &b) { 680 struct mdbg_hdr *hdr = (struct mdbg_hdr *)b; 681 682 assert_header(hdr); 683 684 if (bufdump > 0) { 685 const char *fname = hdr->fname; 686 687 if (!fname) 688 fname = "unknown"; 689 690 IMSG("buffer: %d bytes %s:%d", 691 hdr->pl_size, fname, hdr->line); 692 } 693 } 694 695 malloc_unlock(ctx, exceptions); 696 } 697 698 void mdbg_check(int bufdump) 699 { 700 gen_mdbg_check(&malloc_ctx, bufdump); 701 } 702 #endif 703 704 /* 705 * If malloc debug is enabled, malloc() and friends are redirected by macros 706 * to __mdbg_alloc() etc. 707 * We still want to export the standard entry points in case they are referenced 708 * by the application, either directly or via external libraries. 709 */ 710 711 #undef malloc 712 void *malloc(size_t size) 713 { 714 return mem_alloc(MAF_NULL, NULL, 1, 1, size, __FILE__, __LINE__); 715 } 716 717 #undef malloc_flags 718 void *malloc_flags(uint32_t flags, void *ptr, size_t alignment, size_t size) 719 { 720 return mem_alloc(flags, ptr, alignment, 1, size, __FILE__, __LINE__); 721 } 722 723 #undef calloc 724 void *calloc(size_t nmemb, size_t size) 725 { 726 return mem_alloc(MAF_ZERO_INIT, NULL, 1, nmemb, size, __FILE__, 727 __LINE__); 728 } 729 730 #undef realloc 731 void *realloc(void *ptr, size_t size) 732 { 733 return mem_alloc(MAF_NULL, ptr, 1, 1, size, __FILE__, __LINE__); 734 } 735 736 #undef memalign 737 void *memalign(size_t alignment, size_t size) 738 { 739 return mem_alloc(MAF_NULL, NULL, alignment, 1, size, __FILE__, 740 __LINE__); 741 } 742 743 #if __STDC_VERSION__ >= 201112L 744 #undef aligned_alloc 745 void *aligned_alloc(size_t alignment, size_t size) 746 { 747 if (size % alignment) 748 return NULL; 749 750 return mem_alloc(MAF_NULL, NULL, alignment, 1, size, __FILE__, 751 __LINE__); 752 } 753 #endif /* __STDC_VERSION__ */ 754 755 void free(void *ptr) 756 { 757 free_flags(MAF_NULL, ptr); 758 } 759 760 void free_wipe(void *ptr) 761 { 762 free_flags(MAF_FREE_WIPE, ptr); 763 } 764 765 static void gen_malloc_add_pool(struct malloc_ctx *ctx, void *buf, size_t len) 766 { 767 uint32_t exceptions = malloc_lock(ctx); 768 769 raw_malloc_add_pool(ctx, buf, len); 770 malloc_unlock(ctx, exceptions); 771 } 772 773 static bool gen_malloc_buffer_is_within_alloced(struct malloc_ctx *ctx, 774 void *buf, size_t len) 775 { 776 uint32_t exceptions = malloc_lock(ctx); 777 bool ret = false; 778 779 ret = raw_malloc_buffer_is_within_alloced(ctx, buf, len); 780 malloc_unlock(ctx, exceptions); 781 782 return ret; 783 } 784 785 static bool gen_malloc_buffer_overlaps_heap(struct malloc_ctx *ctx, 786 void *buf, size_t len) 787 { 788 bool ret = false; 789 uint32_t exceptions = malloc_lock(ctx); 790 791 ret = raw_malloc_buffer_overlaps_heap(ctx, buf, len); 792 malloc_unlock(ctx, exceptions); 793 return ret; 794 } 795 796 size_t raw_malloc_get_ctx_size(void) 797 { 798 return sizeof(struct malloc_ctx); 799 } 800 801 void raw_malloc_init_ctx(struct malloc_ctx *ctx) 802 { 803 memset(ctx, 0, sizeof(*ctx)); 804 ctx->poolset.freelist.ql.flink = &ctx->poolset.freelist; 805 ctx->poolset.freelist.ql.blink = &ctx->poolset.freelist; 806 } 807 808 void raw_malloc_add_pool(struct malloc_ctx *ctx, void *buf, size_t len) 809 { 810 const size_t min_len = sizeof(struct bhead) + sizeof(struct bfhead); 811 uintptr_t start = (uintptr_t)buf; 812 uintptr_t end = start + len; 813 void *p = NULL; 814 size_t l = 0; 815 816 start = ROUNDUP(start, SizeQuant); 817 end = ROUNDDOWN(end, SizeQuant); 818 819 if (start > end || (end - start) < min_len) { 820 DMSG("Skipping too small pool"); 821 return; 822 } 823 824 /* First pool requires a bigger size */ 825 if (!ctx->pool_len && (end - start) < MALLOC_INITIAL_POOL_MIN_SIZE) { 826 DMSG("Skipping too small initial pool"); 827 return; 828 } 829 830 tag_asan_free((void *)start, end - start); 831 bpool((void *)start, end - start, &ctx->poolset); 832 l = ctx->pool_len + 1; 833 p = realloc_unlocked(ctx, ctx->pool, sizeof(struct malloc_pool) * l); 834 assert(p); 835 ctx->pool = p; 836 ctx->pool[ctx->pool_len].buf = (void *)start; 837 ctx->pool[ctx->pool_len].len = end - start; 838 #ifdef BufStats 839 ctx->mstats.size += ctx->pool[ctx->pool_len].len; 840 #endif 841 ctx->pool_len = l; 842 } 843 844 bool raw_malloc_buffer_overlaps_heap(struct malloc_ctx *ctx, 845 void *buf, size_t len) 846 { 847 uintptr_t buf_start = (uintptr_t)strip_tag(buf); 848 uintptr_t buf_end = buf_start + len; 849 size_t n = 0; 850 851 raw_malloc_validate_pools(ctx); 852 853 for (n = 0; n < ctx->pool_len; n++) { 854 uintptr_t pool_start = (uintptr_t)strip_tag(ctx->pool[n].buf); 855 uintptr_t pool_end = pool_start + ctx->pool[n].len; 856 857 if (buf_start > buf_end || pool_start > pool_end) 858 return true; /* Wrapping buffers, shouldn't happen */ 859 860 if ((buf_start >= pool_start && buf_start < pool_end) || 861 (buf_end > pool_start && buf_end < pool_end)) 862 return true; 863 } 864 865 return false; 866 } 867 868 bool raw_malloc_buffer_is_within_alloced(struct malloc_ctx *ctx, 869 void *buf, size_t len) 870 { 871 struct bpool_iterator itr = { }; 872 void *b = NULL; 873 uint8_t *start_buf = strip_tag(buf); 874 uint8_t *end_buf = start_buf + len; 875 876 raw_malloc_validate_pools(ctx); 877 878 /* Check for wrapping */ 879 if (start_buf > end_buf) 880 return false; 881 882 BPOOL_FOREACH(ctx, &itr, &b) { 883 uint8_t *start_b = NULL; 884 uint8_t *end_b = NULL; 885 size_t s = 0; 886 887 start_b = strip_tag(get_payload_start_size(b, &s)); 888 end_b = start_b + s; 889 if (start_buf >= start_b && end_buf <= end_b) 890 return true; 891 } 892 893 return false; 894 } 895 896 #ifdef CFG_WITH_STATS 897 void raw_malloc_get_stats(struct malloc_ctx *ctx, struct pta_stats_alloc *stats) 898 { 899 memcpy_unchecked(stats, &ctx->mstats, sizeof(*stats)); 900 stats->allocated = ctx->poolset.totalloc; 901 stats->free2_sum = ctx->poolset.free2_sum; 902 } 903 #endif 904 905 void malloc_add_pool(void *buf, size_t len) 906 { 907 gen_malloc_add_pool(&malloc_ctx, buf, len); 908 } 909 910 bool malloc_buffer_is_within_alloced(void *buf, size_t len) 911 { 912 return gen_malloc_buffer_is_within_alloced(&malloc_ctx, buf, len); 913 } 914 915 bool malloc_buffer_overlaps_heap(void *buf, size_t len) 916 { 917 return gen_malloc_buffer_overlaps_heap(&malloc_ctx, buf, len); 918 } 919 920 #ifdef CFG_NS_VIRTUALIZATION 921 922 #ifndef ENABLE_MDBG 923 924 void *nex_malloc(size_t size) 925 { 926 return mem_alloc(MAF_NEX, NULL, 1, 1, size, __FILE__, __LINE__); 927 } 928 929 void *nex_calloc(size_t nmemb, size_t size) 930 { 931 return mem_alloc(MAF_NEX | MAF_ZERO_INIT, NULL, 1, nmemb, size, 932 __FILE__, __LINE__); 933 } 934 935 void *nex_realloc(void *ptr, size_t size) 936 { 937 return mem_alloc(MAF_NEX, ptr, 1, 1, size, __FILE__, __LINE__); 938 } 939 940 void *nex_memalign(size_t alignment, size_t size) 941 { 942 return mem_alloc(MAF_NEX, NULL, alignment, 1, size, __FILE__, __LINE__); 943 } 944 945 #else /* ENABLE_MDBG */ 946 947 void nex_mdbg_check(int bufdump) 948 { 949 gen_mdbg_check(&nex_malloc_ctx, bufdump); 950 } 951 952 #endif /* ENABLE_MDBG */ 953 954 void nex_free(void *ptr) 955 { 956 free_flags(MAF_NEX, ptr); 957 } 958 959 void nex_malloc_add_pool(void *buf, size_t len) 960 { 961 gen_malloc_add_pool(&nex_malloc_ctx, buf, len); 962 } 963 964 bool nex_malloc_buffer_is_within_alloced(void *buf, size_t len) 965 { 966 return gen_malloc_buffer_is_within_alloced(&nex_malloc_ctx, buf, len); 967 } 968 969 bool nex_malloc_buffer_overlaps_heap(void *buf, size_t len) 970 { 971 return gen_malloc_buffer_overlaps_heap(&nex_malloc_ctx, buf, len); 972 } 973 974 #ifdef BufStats 975 976 void nex_malloc_reset_stats(void) 977 { 978 gen_malloc_reset_stats(&nex_malloc_ctx); 979 } 980 981 void nex_malloc_get_stats(struct pta_stats_alloc *stats) 982 { 983 gen_malloc_get_stats(&nex_malloc_ctx, stats); 984 } 985 986 #endif 987 988 #endif 989