Loading...
src/instrumentation.c libmalloc-657.80.3 libmalloc-792.80.2
--- libmalloc/libmalloc-657.80.3/src/instrumentation.c
+++ libmalloc/libmalloc-792.80.2/src/instrumentation.c
@@ -0,0 +1,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