mirror of
				https://github.com/GrapheneOS/hardened_malloc.git
				synced 2025-10-31 00:06:33 +01:00 
			
		
		
		
	add basic documentation on memory tagging approach
This commit is contained in:
		
							parent
							
								
									9398805fd8
								
							
						
					
					
						commit
						9cc0ac3efa
					
				
					 2 changed files with 75 additions and 1 deletions
				
			
		
							
								
								
									
										2
									
								
								LICENSE
									
										
									
									
									
								
							
							
						
						
									
										2
									
								
								LICENSE
									
										
									
									
									
								
							|  | @ -1,4 +1,4 @@ | |||
| Copyright (c) 2018 Daniel Micay | ||||
| Copyright (c) 2019 Daniel Micay | ||||
| 
 | ||||
| Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
| of this software and associated documentation files (the "Software"), to deal | ||||
|  |  | |||
							
								
								
									
										74
									
								
								README.md
									
										
									
									
									
								
							
							
						
						
									
										74
									
								
								README.md
									
										
									
									
									
								
							|  | @ -402,6 +402,80 @@ size for 2048 byte spacing and the next spacing class matches the page size of | |||
| classes required to avoid substantial waste from rounding. Further slab | ||||
| allocation size classes may be offered as an option in the future. | ||||
| 
 | ||||
| # Memory tagging | ||||
| 
 | ||||
| Integrating extensive support for ARMv8.5 memory tagging is planned and this | ||||
| section will be expanded cover the details on the chosen design. The approach | ||||
| for slab allocations is currently covered, but it can also be used for the | ||||
| allocator metadata region and large allocations. | ||||
| 
 | ||||
| Memory allocations are already always multiples of naturally aligned 16 byte | ||||
| units, so memory tags are a natural fit into a malloc implementation due to the | ||||
| 16 byte alignment requirement. The only extra memory consumption will come from | ||||
| the hardware supported storage for the tag values (4 bits per 16 bytes). | ||||
| 
 | ||||
| The baseline policy will be to generate random tags for each slab allocation | ||||
| slot on first use. The highest value will be reserved for marking freed memory | ||||
| allocations to detect any accesses to freed memory so it won't be part of the | ||||
| generated range. Adjacent slots will be guaranteed to have distinct memory tags | ||||
| in order to guarantee that linear overflows are detected. There are a few ways | ||||
| of implementing this and it will end up depending on the performance costs of | ||||
| different approaches. If there's an efficient way to fetch the adjacent tag | ||||
| values without wasting extra memory, it will be possible to check for them and | ||||
| skip them either by generating a new random value in a loop or incrementing | ||||
| past them since the tiny bit of bias wouldn't matter. Another approach would be | ||||
| alternating odd and even tag values but that would substantially reduce the | ||||
| overall randomness of the tags and there's very little entropy from the start. | ||||
| 
 | ||||
| Once a slab allocation has been freed, the tag will be set to the reserved | ||||
| value for free memory and the previous tag value will be stored inside the | ||||
| allocation itself. The next time the slot is allocated, the chosen tag value | ||||
| will be the previous value incremented by one to provide use-after-free | ||||
| detection between generations of allocations. The stored tag will be wiped | ||||
| before retagging the memory, to avoid leaking it and as part of preserving the | ||||
| security property of newly allocated memory being zeroed due to zero-on-free. | ||||
| It will eventually wrap all the way around, but this ends up providing a strong | ||||
| guarantee for many allocation cycles due to the combination of 4 bit tags with | ||||
| the FIFO quarantine feature providing delayed free. It also benefits from | ||||
| random slot allocation and the randomized portion of delayed free, which result | ||||
| in a further delay along with preventing a deterministic bypass by forcing a | ||||
| reuse after a certain number of allocation cycles. Similarly to the initial tag | ||||
| generation, tag values for adjacent allocations will be skipped by incrementing | ||||
| past them. | ||||
| 
 | ||||
| For example, consider this slab of allocations that are not yet used with 16 | ||||
| representing the tag for free memory. For the sake of simplicity, there will be | ||||
| no quarantine or other slabs for this example: | ||||
| 
 | ||||
|     | 16 | 16 | 16 | 16 | 16 | 16 | | ||||
| 
 | ||||
| Three slots are randomly chosen for allocations, with random tags assigned (2, | ||||
| 15, 7) since these slots haven't ever been used and don't have saved values: | ||||
| 
 | ||||
|     | 16 | 2  | 16 | 15 |  7 | 16 | | ||||
| 
 | ||||
| The 2nd allocation slot is freed, and is set back to the tag for free memory | ||||
| (16), but with the previous tag value stored in the freed space: | ||||
| 
 | ||||
|     | 16 | 16 | 16 | 7  | 15 | 16 | | ||||
| 
 | ||||
| The first slot is allocated for the first time, receiving the random value 3: | ||||
| 
 | ||||
|     | 3  | 16 | 16 | 7  | 15 | 16 | | ||||
| 
 | ||||
| The 2nd slot is randomly chosen again, so the previous tag (2) is retrieved and | ||||
| incremented to 3 as part of the use-after-free mitigation. An adjacent | ||||
| allocation already uses the tag 3, so the tag is further incremented to 4 (it | ||||
| would be incremented to 5 if one of the adjacent tags was 4): | ||||
| 
 | ||||
|     | 3  | 4  | 16 | 7  | 15 | 16 | | ||||
| 
 | ||||
| The last slot is randomly chosen for the next alocation, and is assigned the | ||||
| random value 15. However, it's placed next to an allocation with the tag 15 so | ||||
| the tag is incremented and wraps around to 0: | ||||
| 
 | ||||
|     | 3  | 4  | 16 | 7  | 15 | 0 | | ||||
| 
 | ||||
| # API extensions | ||||
| 
 | ||||
| The `void free_sized(void *ptr, size_t expected_size)` function exposes the | ||||
|  |  | |||
		Loading…
	
	Add table
		
		Reference in a new issue