Loading...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 | // We need to include "internal.h" (which includes platform.h) // before we can use CONFIG_MTE. #include "internal.h" #if CONFIG_MTE MALLOC_NOEXPORT uint8_t * memtag_assign_tag(uint8_t *address, size_t size) { // Exclude the canonical tag by default. uint64_t mask = 0x0001; // Exclude the tag currently associated with the given block. mask = _memtag_exclude_tag(address, mask); // Exclude the tag associated with the previous block. // Keep the check within the page boundary, to avoid hitting potentially // unmapped memory. if (memtag_p2align(address, PAGE_SIZE) == memtag_p2align(address - 16, PAGE_SIZE)) { mask = _memtag_exclude_tag(address - 16, mask); } // Exclude the tag associated with the next block. if (memtag_p2align(address + size - 1, PAGE_SIZE) == memtag_p2align(address + size, PAGE_SIZE)) { mask = _memtag_exclude_tag(address + size, mask); } return _memtag_create_random_tag(address, mask); } MALLOC_NOEXPORT uint8_t * memtag_init_chunk(uint8_t *chunk_start, size_t chunk_size, uint64_t block_size) { size_t num_blocks = chunk_size / block_size; uint8_t *tagged_addr = NULL; uint8_t *first_block = NULL; for (size_t idx = 0; idx < num_blocks; idx++) { uint8_t *block_addr = &chunk_start[idx * block_size]; // Exclude the canonical tag by default. uint64_t exclude_mask = 0x0001; // Exclude the tag of the previously tagged block if (tagged_addr != NULL) { exclude_mask = _memtag_update_mask(tagged_addr, exclude_mask); } tagged_addr = _memtag_create_random_tag(block_addr, exclude_mask); if (idx == 0) { first_block = tagged_addr; } memtag_set_tag(tagged_addr, block_size); } return first_block; } #ifndef DARWINTEST bool memtag_handle_mismatch(void *ptr) { #if !MALLOC_TARGET_EXCLAVES // Speculatively set the crash log message: this is required to inform the // client in case we crash while trying to load the tag (ldg) for the // pointer we were given, which might be a totally invalid value. // Note that the exception generated in this case is not an MTE violation. _os_set_crash_log_cause_and_message((uintptr_t)ptr, "BUG IN CLIENT OF LIBMALLOC: pointer being freed was not valid"); #endif // Load the physical tag for the pointer. const uint8_t *__unsafe_indexable ldg = memtag_fixup_ptr(ptr); if (!memtag_tags_match(ptr, ldg)) { // Extract the 4-bit tags, both for the logical and the physical tag. // Then, compute an 8-bit value encoding the expected logical tag in the // higher bits, and the physical tag in the lower bits. // This value is then used as the crash report reason. const uintptr_t ltag = ((uintptr_t)ptr) >> 56 & 0xf; const uintptr_t ptag = ((uintptr_t)ldg) >> 56 & 0xf; const uint8_t encoded = (ltag << 4) | ptag; #if !MALLOC_TARGET_EXCLAVES _os_set_crash_log_cause_and_message(encoded, "BUG IN CLIENT OF LIBMALLOC: MTE tag mismatch" " (probable double-free)"); // Dereference the pointer carrying the invalid tag. *(volatile char *)ptr; // If we survived that, we must be in soft mode. _os_set_crash_log_cause_and_message(encoded, "BUG IN CLIENT OF LIBMALLOC: ignored previous invalid free" " due to MTE tag mismatch in soft mode (probable double-free)"); // We'll now retry the free() with the correct tag: if there's anything // else wrong other than the tag that will result in a normal abort, and // if there isn't then the block will have been free()d and we'll signal // to the caller to continue. find_zone_and_free((void *)ldg, false); return true; #else // !MALLOC_TARGET_EXCLAVES // For Exclaves, we currently do not have an equivalent way of setting // a crash log message as _os_set_crash_log_cause_and_message. Since // the different context is less susceptible to inadvertently turning // fatal exceptions into catchable ones, for the moment we simply abort. __liblibc_fatal_error( "BUG IN CLIENT OF LIBMALLOC (%llu): MTE tag mismatch", (uint64_t)encoded); #endif // !MALLOC_TARGET_EXCLAVES } return false; } #endif // DARWINTEST #endif // CONFIG_MTE |