From 72681899337a839249cf873bf22ef10dff23c67f Mon Sep 17 00:00:00 2001 From: Dmitry Muhomor Date: Tue, 23 Jan 2024 19:50:26 +0200 Subject: [PATCH] mte: use tag 0 for freed slots, stop reserving tag 15 --- README.md | 20 +++++++++----------- androidtest/memtag/memtag_test.cc | 8 ++++---- h_malloc.c | 5 ++--- memtag.h | 3 ++- 4 files changed, 17 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index 76a4f6d..bccafc2 100644 --- a/README.md +++ b/README.md @@ -724,15 +724,15 @@ freeing as there would be if the kernel supported these features directly. ## Memory tagging -Random tags are set for all slab allocations when allocated, with 5 excluded values: +Random tags are set for all slab allocations when allocated, with 4 excluded values: -1. the default `0` tag -2. a statically *reserved free tag* -3. the previous tag used for the slot -4. the current (or previous) tag used for the slot to the left -5. the current (or previous) tag used for the slot to the right +1. the reserved `0` tag +2. the previous tag used for the slot +3. the current (or previous) tag used for the slot to the left +4. the current (or previous) tag used for the slot to the right -When a slab allocation is freed, the *reserved free tag* is set for the slot. +When a slab allocation is freed, the reserved `0` tag is set for the slot. +Slab allocation slots are cleared before reuse when memory tagging is enabled. This ensures the following properties: @@ -740,10 +740,8 @@ This ensures the following properties: - Use-after-free are deterministically detected until the freed slot goes through both the random and FIFO quarantines, gets allocated again, goes through both quarantines again and then finally gets allocated again for a 2nd time. - Since the default `0` tag isn't used, untagged memory can't access malloc allocations - and vice versa, although it may make sense to reuse the default tag for free - data to avoid reducing the possible random tags from 15 to 14, since freed - data is always zeroed anyway. +- Since the default `0` tag is reserved, untagged pointers can't access slab + allocations and vice versa. Slab allocations are done in a statically reserved region for each size class and all metadata is in a statically reserved region, so interactions between diff --git a/androidtest/memtag/memtag_test.cc b/androidtest/memtag/memtag_test.cc index 910ef5b..5083636 100644 --- a/androidtest/memtag/memtag_test.cc +++ b/androidtest/memtag/memtag_test.cc @@ -47,9 +47,9 @@ void *set_pointer_tag(void *ptr, u8 tag) { // This test checks that slab slot allocation uses tag that is distint from tags of its neighbors // and from the tag of the previous allocation that used the same slot void tag_distinctness() { - // 0 and 15 are reserved + // tag 0 is reserved const int min_tag = 1; - const int max_tag = 14; + const int max_tag = 0xf; struct SizeClass { int size; @@ -148,8 +148,8 @@ void tag_distinctness() { } } - // check that all of the tags were used, except reserved ones - assert(seen_tags == (0xffff & ~(1 << 0 | 1 << 15))); + // check that all of the tags were used, except for the reserved tag 0 + assert(seen_tags == (0xffff & ~(1 << 0))); printf("size_class\t%i\t" "tdc_left %i\t" "tdc_right %i\t" "tdc_prev_alloc %i\n", sc.size, left_neighbor_tdc_cnt, right_neighbor_tdc_cnt, prev_alloc_tdc_cnt); diff --git a/h_malloc.c b/h_malloc.c index 014b461..15be0a2 100644 --- a/h_malloc.c +++ b/h_malloc.c @@ -574,9 +574,8 @@ static void *tag_and_clear_slab_slot(struct slab_metadata *metadata, void *slot_ // is constructed. u8 *slot_tags = metadata->arm_mte_tags; - // Tag exclusion mask. 0 tag is always excluded to detect accesses to slab memory via untagged - // pointers. Moreover, 0 tag is excluded in bionic via PR_MTE_TAG_MASK prctl - u64 tem = (1 << 0) | (1 << RESERVED_TAG); + // tag exclusion mask + u64 tem = (1 << RESERVED_TAG); // current or previous tag of left neighbor or 0 if there's no left neighbor or if it was never used tem |= (1 << u4_arr_get(slot_tags, slot_idx)); diff --git a/memtag.h b/memtag.h index 0ba4cbc..e431283 100644 --- a/memtag.h +++ b/memtag.h @@ -6,7 +6,8 @@ #ifdef HAS_ARM_MTE #include "arm_mte.h" #define MEMTAG 1 -#define RESERVED_TAG 15 +// Note that bionic libc always reserves tag 0 via PR_MTE_TAG_MASK prctl +#define RESERVED_TAG 0 #define TAG_WIDTH 4 #endif