mirror of
				https://github.com/GrapheneOS/hardened_malloc.git
				synced 2025-11-03 01:06:33 +01:00 
			
		
		
		
	mte: use tag 0 for freed slots, stop reserving tag 15
This commit is contained in:
		
							parent
							
								
									89a7bc631f
								
							
						
					
					
						commit
						7b22192409
					
				
					 4 changed files with 17 additions and 19 deletions
				
			
		
							
								
								
									
										20
									
								
								README.md
									
										
									
									
									
								
							
							
						
						
									
										20
									
								
								README.md
									
										
									
									
									
								
							| 
						 | 
					@ -724,15 +724,15 @@ freeing as there would be if the kernel supported these features directly.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
## Memory tagging
 | 
					## 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
 | 
					1. the reserved `0` tag
 | 
				
			||||||
2. a statically *reserved free tag*
 | 
					2. the previous tag used for the slot
 | 
				
			||||||
3. 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 left
 | 
					4. the current (or previous) tag used for the slot to the right
 | 
				
			||||||
5. 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:
 | 
					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
 | 
					- Use-after-free are deterministically detected until the freed slot goes through
 | 
				
			||||||
  both the random and FIFO quarantines, gets allocated again, goes through both
 | 
					  both the random and FIFO quarantines, gets allocated again, goes through both
 | 
				
			||||||
  quarantines again and then finally gets allocated again for a 2nd time.
 | 
					  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
 | 
					- Since the default `0` tag is reserved, untagged pointers can't access slab 
 | 
				
			||||||
  and vice versa, although it may make sense to reuse the default tag for free
 | 
					  allocations and vice versa.
 | 
				
			||||||
  data to avoid reducing the possible random tags from 15 to 14, since freed
 | 
					 | 
				
			||||||
  data is always zeroed anyway.
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
Slab allocations are done in a statically reserved region for each size class
 | 
					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
 | 
					and all metadata is in a statically reserved region, so interactions between
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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
 | 
					// 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
 | 
					// and from the tag of the previous allocation that used the same slot
 | 
				
			||||||
void tag_distinctness() {
 | 
					void tag_distinctness() {
 | 
				
			||||||
    // 0 and 15 are reserved
 | 
					    // tag 0 is reserved
 | 
				
			||||||
    const int min_tag = 1;
 | 
					    const int min_tag = 1;
 | 
				
			||||||
    const int max_tag = 14;
 | 
					    const int max_tag = 0xf;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    struct SizeClass {
 | 
					    struct SizeClass {
 | 
				
			||||||
        int size;
 | 
					        int size;
 | 
				
			||||||
| 
						 | 
					@ -148,8 +148,8 @@ void tag_distinctness() {
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        // check that all of the tags were used, except reserved ones
 | 
					        // check that all of the tags were used, except for the reserved tag 0
 | 
				
			||||||
        assert(seen_tags == (0xffff & ~(1 << 0 | 1 << 15)));
 | 
					        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",
 | 
					        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);
 | 
					               sc.size, left_neighbor_tdc_cnt, right_neighbor_tdc_cnt, prev_alloc_tdc_cnt);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -574,9 +574,8 @@ static void *tag_and_clear_slab_slot(struct slab_metadata *metadata, void *slot_
 | 
				
			||||||
    // is constructed.
 | 
					    // is constructed.
 | 
				
			||||||
    u8 *slot_tags = metadata->arm_mte_tags;
 | 
					    u8 *slot_tags = metadata->arm_mte_tags;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Tag exclusion mask. 0 tag is always excluded to detect accesses to slab memory via untagged
 | 
					    // tag exclusion mask
 | 
				
			||||||
    // pointers. Moreover, 0 tag is excluded in bionic via PR_MTE_TAG_MASK prctl
 | 
					    u64 tem = (1 << RESERVED_TAG);
 | 
				
			||||||
    u64 tem = (1 << 0) | (1 << RESERVED_TAG);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // current or previous tag of left neighbor or 0 if there's no left neighbor or if it was never used
 | 
					    // 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));
 | 
					    tem |= (1 << u4_arr_get(slot_tags, slot_idx));
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										3
									
								
								memtag.h
									
										
									
									
									
								
							
							
						
						
									
										3
									
								
								memtag.h
									
										
									
									
									
								
							| 
						 | 
					@ -6,7 +6,8 @@
 | 
				
			||||||
#ifdef HAS_ARM_MTE
 | 
					#ifdef HAS_ARM_MTE
 | 
				
			||||||
#include "arm_mte.h"
 | 
					#include "arm_mte.h"
 | 
				
			||||||
#define MEMTAG 1
 | 
					#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
 | 
					#define TAG_WIDTH 4
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		
		Reference in a new issue